是否可以對一行文字中的單字中的字母進行排序?

是否可以對一行文字中的單字中的字母進行排序?

因此,我有一個充滿測試命令的文件,我喜歡對我的一些函數運行這些命令,以確保它們正確處理所有可能的情況。雖然有重複的命令是沒有意義的。以下是一些範例:

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'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並在循環後對它們進行操作,我們可以避免多次對重複的選項進行操作。

相關內容