Awk 使用linux命令对第二列进行排序

Awk 使用linux命令对第二列进行排序,awk,sed,grep,Awk,Sed,Grep,可以对文本进行水平排序吗? 例如,我有一个拼写文件,其中包含所有英文单词,后跟标签。(它可能包含unicode文本和数百万个单词) 我需要对标签进行排序(最好先是小写字母,然后是大写字母) 预期: test/acABC this/PQR line/MNP again/xX 我可以用熊猫做这个。但是我想知道我是否可以只用linux命令来完成这项任务 import pandas as pd df = pd.read_csv('test.csv', sep='/', header=None) df.

可以对文本进行水平排序吗? 例如,我有一个拼写文件,其中包含所有英文单词,后跟标签。(它可能包含unicode文本和数百万个单词)

我需要对标签进行排序(最好先是小写字母,然后是大写字母) 预期:

test/acABC
this/PQR
line/MNP
again/xX
我可以用熊猫做这个。但是我想知道我是否可以只用linux命令来完成这项任务

import pandas as pd
df = pd.read_csv('test.csv', sep='/', header=None)
df.columns = ['word', 'tags']
df['tags']=df['tags'].map(lambda x: ''.join(sorted([i for i in x])))
df['final'] = df['word'] + '/' + df['tags'] 
df['final'].to_csv('result.csv', index=False, header=None)
这可能适用于您(GNU sed和排序):

交换第二个字段中的大写字母和小写字母,然后对第二个字段中的结果进行排序,而不考虑大小写

如果大小写字母相互缠绕,请使用:

sed -E ':a;s#/([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)#/\1\3\2#;ta' file |
sort -ft/ -k2,2

我误解了这个问题:

sed -E ':a;s#/([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)#/\1\3\2#;ta' file |
sed -zE 's#/([[:lower:]]*)(.*)#/\n\1\n\2#mg' |
sed '2~3,+1s/.*/echo "&" | sed -z "s#\\B#\\n#g" | sort | sed -z "s#\\n##g"/e' |
sed 'N;N;s/\n//g'
/
后面的小写字母与大写字母分开,并将小写字母放在第一位

将每一行分隔成一个三行记录,第一行是第一个字段,第二行和第三行分别是第二个字段的大写字母和小写字母

每第二行和第三行进行排序,将每一行的每一个字母分成一行。然后对结果行集进行排序,并将行内的行集重新组合为一行

另一种可能更好的选择是:

sed -zE 's/(.*\/)(.*)/\1\n\2/mg' file |
sed -E 'N;s/(.*)\n(.*)/echo "\2"|sed -z "s#\\B#\\n#g"|sort|sed -z "s#\\n##g"|sed "s#^#\1#"/e' |
sed -E ':a;s/\/([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)/\/\1\3\2/;ta'
当然,有一些实用程序可以执行以下操作:

sed -zE 's/(.*\/)(.*)/\1\n\2/mg' file |
sed -E 'N;s/(.*)\n(.*)/echo "\2"|fold -b1|sort|tr -d "\\n"|sed "s#^#\1#"/e' |
sed -E ':a;s/\/([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)/\/\1\3\2/;ta
事实上,解决方案可以在一行上表示为一个替换:

 sed -E 's/^(.*\/)(.*)/echo "\2"|fold -b1|sort|tr -d "\\n"|sed -E ":a;s#^([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)#\\1\\3\\2#;ta;s#^#\1#"/e' file    
这可能适用于您(GNU sed和排序):

交换第二个字段中的大写字母和小写字母,然后对第二个字段中的结果进行排序,而不考虑大小写

如果大小写字母相互缠绕,请使用:

sed -E ':a;s#/([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)#/\1\3\2#;ta' file |
sort -ft/ -k2,2

我误解了这个问题:

sed -E ':a;s#/([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)#/\1\3\2#;ta' file |
sed -zE 's#/([[:lower:]]*)(.*)#/\n\1\n\2#mg' |
sed '2~3,+1s/.*/echo "&" | sed -z "s#\\B#\\n#g" | sort | sed -z "s#\\n##g"/e' |
sed 'N;N;s/\n//g'
/
后面的小写字母与大写字母分开,并将小写字母放在第一位

将每一行分隔成一个三行记录,第一行是第一个字段,第二行和第三行分别是第二个字段的大写字母和小写字母

每第二行和第三行进行排序,将每一行的每一个字母分成一行。然后对结果行集进行排序,并将行内的行集重新组合为一行

另一种可能更好的选择是:

sed -zE 's/(.*\/)(.*)/\1\n\2/mg' file |
sed -E 'N;s/(.*)\n(.*)/echo "\2"|sed -z "s#\\B#\\n#g"|sort|sed -z "s#\\n##g"|sed "s#^#\1#"/e' |
sed -E ':a;s/\/([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)/\/\1\3\2/;ta'
当然,有一些实用程序可以执行以下操作:

sed -zE 's/(.*\/)(.*)/\1\n\2/mg' file |
sed -E 'N;s/(.*)\n(.*)/echo "\2"|fold -b1|sort|tr -d "\\n"|sed "s#^#\1#"/e' |
sed -E ':a;s/\/([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)/\/\1\3\2/;ta
事实上,解决方案可以在一行上表示为一个替换:

 sed -E 's/^(.*\/)(.*)/echo "\2"|fold -b1|sort|tr -d "\\n"|sed -E ":a;s#^([[:lower:]]*)([[:upper:]]+)([[:lower:]]+)#\\1\\3\\2#;ta;s#^#\1#"/e' file    

这在awk中有点尴尬。但有时最好的awk实际上是perl:

perl -F/ -lane 'printf "%s/%s\n", $F[0], join "", sort split //, $F[1];'


上述所有方法都使用相同的原理,但最终的解决方案值得一些解释。
(?=/)
是一个否定的前瞻断言,因此表达式
(?=/)(.*)
匹配行中第一个
/
之后的所有文本,但不使用
/
/
之后的所有字符都被放入第一个匹配组中,以便
排序拆分
可以对它们进行操作。
split//,$1
将匹配组拆分为单个字符,这些字符被传递到
sort
,然后在不使用分隔符的情况下通过联接重新联接。
join/sort/split
的结果被用作匹配模式的替换。

这在awk中有点尴尬。但有时最好的awk实际上是perl:

perl -F/ -lane 'printf "%s/%s\n", $F[0], join "", sort split //, $F[1];'

上述所有方法都使用相同的原理,但最终的解决方案值得一些解释。
(?=/)
是一个否定的前瞻断言,因此表达式
(?=/)(.*)
匹配行中第一个
/
之后的所有文本,但不使用
/
/
之后的所有字符都被放入第一个匹配组中,以便
排序拆分
可以对它们进行操作。
split//,$1
将匹配组拆分为单个字符,这些字符被传递到
sort
,然后在不使用分隔符的情况下通过联接重新联接。
join/sort/split
的结果用作匹配模式的替换。

使用GNU awk表示“sorted_in”,并在指定空分隔符时将字符串拆分为字符:

$ cat tst.awk
BEGIN {
    FS=OFS="/"
    PROCINFO["sorted_in"] = "@val_str_asc"
}
{
    split($2,lets,"")
    $2 = ""
    for (i in lets) {
        $2 = $2 lets[i]
    }
    print
}
要获得小写字母优先于大写字母排序的输出,您必须先找到具有这种排序顺序的区域设置,并在运行脚本之前设置
LC\u ALL=
,或将所有大写字母转换为小写字母,反之亦然,然后进行排序,然后在打印前将它们转换回原来的字符,或者在每个实际字符前面放一个装饰字符,例如所有小写字母都有一个前导
a
,而大写字母则有一个前导
a
,以再次强制执行不同的顺序,例如:

$ cat tst.awk
BEGIN {
    FS=OFS="/"
    PROCINFO["sorted_in"] = "@val_str_asc"
}
{
    split($2,lets,"")

    for (i in lets) {
        lets[i] = ( lets[i] ~ /[[:lower:]]/ ? "A" : "a" ) lets[i]
    }

    $2 = ""
    for (i in lets) {
        $2 = $2 substr(lets[i],2)
    }    
    print
}
使用GNU awk表示“sorted_in”,并在指定空分隔符时将字符串拆分为字符:

$ cat tst.awk
BEGIN {
    FS=OFS="/"
    PROCINFO["sorted_in"] = "@val_str_asc"
}
{
    split($2,lets,"")
    $2 = ""
    for (i in lets) {
        $2 = $2 lets[i]
    }
    print
}
要获得小写字母优先于大写字母排序的输出,您必须先找到具有这种排序顺序的区域设置,并在运行脚本之前设置
LC\u ALL=
,或将所有大写字母转换为小写字母,反之亦然,然后进行排序,然后在打印前将它们转换回原来的字符,或者在每个实际字符前面放一个装饰字符,例如所有小写字母都有一个前导
a
,而大写字母则有一个前导
a
,以再次强制执行不同的顺序,例如:

$ cat tst.awk
BEGIN {
    FS=OFS="/"
    PROCINFO["sorted_in"] = "@val_str_asc"
}
{
    split($2,lets,"")

    for (i in lets) {
        lets[i] = ( lets[i] ~ /[[:lower:]]/ ? "A" : "a" ) lets[i]
    }

    $2 = ""
    for (i in lets) {
        $2 = $2 substr(lets[i],2)
    }    
    print
}

下面是一个使用
perl
的替代解决方案,它首先给出小写字母:

$perl-F'/'-lane'$s=join',排序拆分/,$F[1];
打印$F[0]、“/”、$s=~s/^([A-Z]++)(.+)/$2$1/r'ip.txt
测试/测试
本文件/PQR
线路/MNP
再次/xX
另一种选择:

$perl-pe的|.*/\K.+| join(“,sort split//,$&)=~s/^([A-Z]+)(.+)/$2$1/r | e'ip.txt
测试/测试
本文件/PQR
线路/MNP
再次/xX

这里有一个使用
perl
的替代解决方案,它首先给出小写字母:

$perl-F'/'-lane'$s=join',排序拆分/,$F[1];
打印$F[0]、“/”、$s=~s/^([A-Z]++)(.+)/$2$1/r'ip.txt
测试/测试
本文件/PQR
线路/MNP
再次/x