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

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

そこで、いくつかの関数に対して実行して、考えられるすべての状況を正しく処理しているかどうかを確認するテスト コマンドが満載のファイルを用意しました。ただし、コマンドが重複しても意味がありません。次に例を示します。

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

小文字を大文字の前に置かなければならないという追加の要件については、ASCII では で'x'ある'X' ^ 32(および で'X'ある'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

ご要望に応じて、すべての小文字オプションを大文字オプションの前に並べ替える 1 つの方法 (おそらく最適ではない) を次に示します。

$ 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、ループ後にそれらを操作すると、重複したオプションが複数回操作されることが回避されることに注意してください。

関連情報