是否可以对一行文本中的单词中的字母进行排序?

是否可以对一行文本中的单词中的字母进行排序?

因此,我有一个充满测试命令的文件,我喜欢对我的一些函数运行这些命令,以确保它们正确处理所有可能的情况。虽然有重复的命令是没有意义的。以下是一些示例:

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并在循环后对它们进行操作,我们可以避免多次对重复的选项进行操作。

相关内容