テキスト行の単語内で文字を並べ替えることは可能ですか?

テキスト行の単語内で文字を並べ替えることは可能ですか?

したがって、すべての可能な状況を正しく処理することを確認するために、いくつかの機能に対して実行したいテストコマンドでいっぱいのファイルがあります。しかし、重複したコマンドを使用することは意味がありません。ここにいくつかの例があります。

rap ,Xflg MIT X11           
rap ,XPBfl 'MITER'
rap ,Bflg share git-grep    
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11

...私の関数 "rap"はダッシュの代わりにカンマを使用して文字オプションの始まりを表示し、その後にいくつかの引数が続きます。これらのオプションの順序は重要ではありません。

rap ,Bf X11
rap ,fB X11

...全く同じコマンドです。もちろん、ファイルから重複した行を削除するのは簡単ですが、上記の問題を避けるために私が望むのは、上記の結果になるようにオプションをアルファベット順に並べ替えることです。

rap ,Bf X11
rap ,Bf X11

...その後、重複したアイテムを削除できます。英雄主義なしにそのようなことを達成することは可能ですか?これは、オプションのリストをソートするのではなく、オプション自体をソートすることです。

答え1

別のperl変形:

$ perl -pe 's{^rap ,\K\S+}{join "", sort split //, $&}e' file
rap ,Xfgl MIT X11
rap ,BPXfl 'MITER'
rap ,Bfgl share git-grep
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11

'x'大文字の前に小文字を追加する必要がある場合は、ASCIIでis 'X' ^ 32(および'X'is 'x' ^ 32)という事実を利用できます。

$ perl -pe 's{^rap ,\K\S+}{join "", sort {(ord($a)^32) <=> (ord($b)^32)} split //, $&}e' file
rap ,fglX MIT X11
rap ,flBPX 'MITER'
rap ,fglB share git-grep
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11

答え2

Perl を使用すると、カンマの後の単語文字シーケンスをキャプチャし、結果を配列に分割して並べ替え、結果を置き換えることができます。

$ perl -pe 's{(?<=,)(\w+)}{join "", sort split(//, $1)}e' yourfile 
rap ,Xfgl MIT X11           
rap ,BPXfl 'MITER'
rap ,Bfgl share git-grep    
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11

要求に応じてすべての大文字オプションの前にすべての小文字オプションをソートする(おそらく最適ではないかもしれない)方法は次のとおりです。

$ perl -pe 's{(?<=,)(\w+)}{@opts = split(//,$1); join "", 
    (sort grep /[[:lower:]]/,@opts), (sort grep /[^[:lower:]]/, @opts)
  }e' yourfile 
rap ,fglX MIT X11           
rap ,flBPX 'MITER'
rap ,fglB share git-grep    
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11

答え3

GNU awkの使用sorted_inとにかく私たちはgawkを使用しているので、適用できるいくつかの便利ですが不要な拡張があります。装飾 - 整列 - 脾臓式イディオム1小文字を大文字の前と大文字の前に配置して、小文字を大文字の前に配置し、印刷する前に2これらの装飾を再度削除します。

$ cat tst.awk
BEGIN { PROCINFO["sorted_in"] = "@val_str_asc" }
match( $0, /^(\s*\S+\s*,)(\S+)(.*)/, a ) {
    gsub( /[[:lower:]]/, "1 &,", a[2] )        # Decorate
    gsub( /[[:upper:]]/, "2 &,", a[2] )

    sorted = ""
    split(a[2],opts,",")
    for ( idx in opts ) {                      # Sort
        sorted = sorted opts[idx]
    }

    gsub( /[[:digit:] ,]/, "", sorted )        # Undecorate
    $0 = a[1] sorted a[3]
}
{ print }

$ awk -f tst.awk file
rap ,fglX MIT X11
rap ,flBPX 'MITER'
rap ,fglB share git-grep
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11

答え4

入力ファイルのカンマをダッシュ​​に置き換えると、オプションを使用して通常どおりgetopts関数rapを解析できます。

変更はで行うことができます。行の先頭を に変更するsedと、次のようになります。rap ,rap -

sed 's/^rap ,/rap -/' file.in >file

. ./fileその後、rap関数が以前に宣言されたと仮定すると、スクリプトによって生成されたファイルを簡単にインポートできます。

解析機能rapのオプション:

rap () {
        OPTIND=1

        unset -v B_flag P_flag X_flag
        unset -v b_flag f_flag g_flag l_flag

        while getopts BPXbfgl opt; do
                case $opt in
                        B) B_flag=true ;;
                        P) P_flag=true ;;
                        X) X_flag=true ;;
                        b) b_flag=true ;;
                        f) f_flag=true ;;
                        g) g_flag=true ;;
                        l) l_flag=true ;;
                        *) echo 'Error' >&2; return 1
                esac
        done
        shift "$(( OPTIND - 1 ))"

        # Act on set flags here.

        if "${f_flag-false}"; then
                echo 'The -f option was used'
        fi

        # The non-options are available in "$@".

        printf 'Other argument: %s\n' "$@"
        printf -- '---\n'
}

ループ内でフラグ変数を設定whileし、ループ後にその変数に対して操作を実行すると、冗長オプションに対する操作を複数回防止できます。

関連情報