【问题标题】:Sort grep matches by the characters' location in character classes按字符在字符类中的位置对 grep 匹配项进行排序
【发布时间】:2016-04-19 11:13:05
【问题描述】:

我正在尝试使用 grep 来实现以下目标:

鉴于[mM][aA][rRyY]$abcMAydefmAyghimaR 等 grep 模式都匹配该模式,我想按字符在字符类中的位置对它们进行排序。例如,由于m[mM] 中出现在M 之前,我希望MAy 出现在最后;同样,由于a 出现在[aA] 中的A 之前,我希望maR 出现在mAy 之前。

这绝对不是典型的用法,但我想知道它是否可以轻松完成?

【问题讨论】:

  • 我会使用awk 来输出带有匹配字符位置前缀的行。然后按该列排序。
  • SO 不是免费的编码服务。如果你在bash做复杂的事情,你真的需要学习awk
  • 正则表达式告诉你字符串匹配后,你需要单步遍历字符串的匹配部分。对于每个字符,您需要使用 PHP 中的strpos() 等普通字符串搜索函数来找到它在相应字符类中的位置。
  • 如果您可以从一些对程序更友好的源构建您的正则表达式,这将有所帮助,但基本上我认为您需要按照 Barmar 的建议对您的列表进行后处理。使用自定义排序功能,您可能会更聪明,并按位置对单个字母应用权重,然后让排序功能完成繁重的工作,但我不确定这会更好。
  • 或者您可以让awk 找到字符串的匹配部分及其原始行号,然后使用相同的 awk 脚本解析 RegEx 规则并按匹配的索引对字符串进行排序人物。我推荐 Arnold Robbins 的《Effective Awk Programming, 4th Edition》一书,但与此同时,请发布一些简洁、可测试的示例输入和预期输出,我们可以为您提供帮助。

标签: regex linux bash grep


【解决方案1】:

您可以使用 awk 和 sort 通过装饰/取消装饰模式定义自定义排序顺序。例如

$ echo {m,M}{a,A}{r,R,y,Y} | tr ' ' '\n' | 
  awk -v pat='mMaArRyY' '{for(i=1;i<=length($0);i++) 
                            printf "%s", index(pat,substr($0,i,1)); 
                          print "\t" $0}' | 
  sort | cut -f2-

mar
maR
may
maY
mAr
mAR
mAy
mAY
Mar
MaR
May
MaY
MAr
MAR
MAy
MAY

更新 对于重叠模式 [aA][Aa] 这里是更新的解决方案,以显示如何确定顺序,我没有包括最终剪辑。

$ echo {a,A}{A,a} | tr ' ' '\n' | 
  awk -v pat='aA,Aa' 'BEGIN{n=split(pat,p,",")}
                            {for(i=1;i<=length($0);i++)
                                printf "%s",index(p[i],substr($0,i,1)); 
                             print "\t" $0}' | 
  sort

11      aA
12      aa
21      AA
22      Aa

这是完整的脚本

$ cat text
abcMay defmaY ghiMark jklMaY443 

$ grep -oE "\S*[mM][aA][rRyY]\S*" text
abcMay
defmaY
ghiMark 
jklMaY443

提取模式匹配的子字符串

$ ... | sed -r 's/(\S*([mM][aA][rRyY])\S*)/\2\t\1/'
May     abcMay
maY     defmaY  
Mar     ghiMark                                    
MaY     jklMaY443

$ ... |  awk -v pat='mM,aA,rRyY' 'BEGIN{n=split(pat,p,",")}
                             {for(i=1;i<=length($1);i++)
                                printf "%s",index(p[i],substr($0,i,1));
                              print "\t" $0}'
  | sort

114     maY     defmaY
211     Mar     ghiMark
213     May     abcMay
214     MaY     jklMaY443

一切井井有条,消除假键

... | cut -f3-

defmaY
ghiMark
abcMay
jklMaY443

【讨论】:

  • 他问题中的示例输入是abcMAydefMay。你的解决方案能解决这个问题吗?
  • 看起来您的代码将匹配abc 中的apat,即使它不是正则表达式匹配的一部分。
  • 如果模式类似于[aA][Aa] 怎么办?你会为此输入什么pat?它需要将aA 排序在aaAA 之前。
  • 你应该提取匹配的子字符串来解决第一个问题。如果字符序列重叠,此解决方案将无法正常工作。但是,也可以通过在每次匹配时迭代 pat 变量来修复它。
  • 这些问题使他的问题不像您的解决方案建议的那么简单。
猜你喜欢
  • 1970-01-01
  • 2014-03-03
  • 2013-01-02
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 2015-07-23
  • 1970-01-01
  • 2019-09-20
相关资源
最近更新 更多