提问人:mister entername 提问时间:10/23/2023 最后编辑:John Kugelmanmister entername 更新时间:10/24/2023 访问量:209
按字母顺序将行与字母匹配的 grep 命令
grep command that matches lines with letters in alphabetical order
问:
我需要帮助找出一个带有 grep 的正则表达式,该表达式将搜索文件并显示将 [a-z] 按字母顺序分别放在每个“集合”中的行(示例会变得很清楚)
有效匹配示例:
a96d7e75-4432-41de-835c-625a636c1914 prefranks
b028224d-314b-4b03-a873-1436838f9233 escape
无效匹配示例:
c69f34e8-905e-4ce8-7893-a3e271d6f48c reconvince
e9db0700-f72b-4bea-ae37-e18ec6ca80d3 lumberjacks
我用了:
egrep '^([^a-f-]*a?[^a-f-]*b?[^a-f-]*c?[^a-f-]*d?[^a-f-]*e?[^a-f-]*f?-){4}[^a-f-]*a?[^a-f-]*b?[^a-f-]*c?[^a-f-]*d?[^a-f-]*e?[^a-f-]*f?[0-9]* ' text.txt
它没有给出任何无效的匹配,但它遗漏了如下的有效示例,我无法弄清楚原因:
6cd11113-bcf3-4f73-85f5-145b49225244 neoconservative
96239f18-5c62-495a-b1f8-50759443b885 fellest
51771125-b4d8-4cf8-a3d9-67117263f708 macular
a266f798-d772-47f0-9bdf-451939c2007e buntings
答:
3赞
dawg
10/23/2023
#1
对 Grep 很强硬......
但鉴于:
$ cat file
a96d7e75-4432-41de-835c-625a636c1914 prefranks
b028224d-314b-4b03-a873-1436838f9233 escape
c69f34e8-905e-4ce8-7893-a3e271d6f48c reconvince
e9db0700-f72b-4bea-ae37-e18ec6ca80d3 lumberjacks
您可以使用 Ruby:
ruby -lane 'puts $_ if $F[0].split(/-/).
map{|a| a.scan(/[a-f]/)}.all?{|a| a==a.sort}' file
指纹:
a96d7e75-4432-41de-835c-625a636c1914 prefranks
b028224d-314b-4b03-a873-1436838f9233 escape
或者,任何 awk:
awk '{
num_fields=split($1,fi,"-")
for(f=1; f<=num_fields; f++) {
gsub(/[^a-f]/,"",fi[f])
if (length(fi[f])>1)
for(i=2; i<=length(fi[f]); i++)
if (substr(fi[f],i-1,1)>substr(fi[f],i,1)) next
}
} 1' file
# same output
评论
0赞
Cary Swoveland
10/23/2023
或者,也可以从中去除数字,以产生,然后与 进行比较。由于与具有排序部分的字符串不同,因此此字符串(行)不匹配。我不记得你在之前的评论中提到的问题。我在这里的地方,我无意中在之前的评论中写道。但是,使用可能更好。"aa96d7e75-44d3a2"
s = "aade-da"
s
s.gsub(/[a-z]+/) { |s| s.each_char.sort.join } #=> "aade-ad"
s
gsub
scan
split
5赞
Walter A
10/23/2023
#2
对于后有数字的子字符串,Your 失败。
当您替换为 时,它将起作用,导致egrep
f
f?*-){4}
f?[^a-f]*-){4}
egrep '^([^a-f-]*a?[^a-f-]*b?[^a-f-]*c?[^a-f-]*d?[^a-f-]*e?[^a-f-]*f?[^a-f]*-){4}[^a-f-]*a?[^a-f-]*b?[^a-f-]*c?[^a-f-]*d?[^a-f-]*e?[^a-f-]*f?[0-9]* ' text.txt
当您使用变量时,它同样难以阅读,但更短
x='[^a-f-]'
egrep "^($x*a?$x*b?$x*c?$x*d?$x*e?$x*f?$x*-){4}$x*a?$x*b?$x*c?$x*d?$x*e?$x*f?[0-9]* " text.txt
你可以做一个小循环:
#!/bin/bash
while IFS= read -r line; do
charline="${line//[0-9]/}"
if [[ "$charline" =~ ^(a?b?c?d?e?f?-){4}(a?b?c?d?e?f?)\ .* ]]; then
echo "${line}"
fi
done < text.txt
最后一个解决方案可以做得更小(并且更难阅读):
#!/bin/bash
while IFS= read -r line; do
[[ "${line//[0-9]/}" =~ ^(a?b?c?d?e?f?-){4}(a?b?c?d?e?f?)\ .* ]] &&
echo "${line}"
done < text.txt
编辑:上述解决方案不接受标记中的双字母。
当您想接受这些内容时,请将解决方案更改为
#/bin/bash
while IFS= read -r line; do
[[ "${line//[0-9]/}" =~ ^(a*b*c*d*e*f*-){4}(a*b*c*d*e*f*)\ .* ]] &&
echo "${line}"
done < text.txt
编辑 2:
当您想接受双字母,并且知道输入始终与给定的示例(仅标记、标记之间和最后一个标记后的空格)时,您可以使用[0-9a-f]
-
grep -E '^([a0-9]*[b0-9]*[c0-9]*[d0-9]*[e0-9]*[f0-9]*[- ]){5}' text.txt
评论
2赞
dawg
10/23/2023
如果您有多个相同的字母,例如aa96d7e75-4432...
0赞
Walter A
10/23/2023
@dawg 描述要求按字母顺序排列,但 OP 的代码也带有唯一的字母。OP 问为什么他的代码中没有显示某些行,所以我在他的代码中寻找改进。我添加了一个支持重复字母的解决方案。
4赞
The fourth bird
10/23/2023
#3
您似乎希望在第一个空格之前验证数据的第一部分。这些字符串由字符 a-f 0-9 和连字符组成。
如果你可以在 mac 上使用 或例如在 Mac 上用于与 Perl 兼容的正则表达式,则可以使用负前瞻来确保在第一部分中,匹配后 的范围内没有 char,匹配后等的范围内没有 char。grep -P
ggrep -P
[a-e]
f
[a-d]
e
^(?![a-f\d-]*(?:f\d*[a-e]|e\d*[a-d]|d\d*[abc]|c\d*[ab]|b\d*a))[a-f\d]+(?:-[a-f\d]+){4}
^
字符串的开头(?!
消极的展望,断言向右不是[a-f\d-]*
匹配可选字符 a-f、数字或-
(?:
备选方案的非捕获组f\d*[a-e]
匹配一个 、 可选数字,然后匹配该范围内的一个字符f
[a-e]
|
或e\d*[a-d]
匹配一个 、 可选数字,然后匹配e
[a-d]
|
或d\d*[abc]
同d
|
或c\d*[ab]
同c
|
或b\d*a
同b
)
关闭群组
)
关闭 lookbeahead[a-f\d]+
匹配 1+ 个字符 a-f 或数字(?:-[a-f\d]+){4}
重复 4 次匹配和 1+ 字符 a-f 或数字后跟空格-
示例grep -P
grep -P '^(?![a-f\d-]*(?:f\d*[a-e]|e\d*[a-d]|d\d*[abc]|c\d*[ab]|b\d*a))[a-f\d]+(?:-[a-f\d]+){4} ' text.txt
输出
a96d7e75-4432-41de-835c-625a636c1914 prefranks
b028224d-314b-4b03-a873-1436838f9233 escape
6cd11113-bcf3-4f73-85f5-145b49225244 neoconservative
96239f18-5c62-495a-b1f8-50759443b885 fellest
51771125-b4d8-4cf8-a3d9-67117263f708 macular
a266f798-d772-47f0-9bdf-451939c2007e buntings
观看正则表达式演示
评论
2赞
anubhava
10/23/2023
眼睛疲劳正则表达式:-)
1赞
The fourth bird
10/23/2023
@anubhava 这里不可否认:-)幸运的是,OP已经有点习惯了。
0赞
Walter A
10/24/2023
在我的答案的最后一次编辑中,添加了一个简单的 grep,没有(否定)展望。
1赞
The fourth bird
10/24/2023
@WalterA 是的,但这也匹配或 5 个空格-----
1赞
Walter A
10/24/2023
@Thefourthbird 我想为行为良好的输入提供一个简单的解决方案。支持是可能的-----
grep -E '^([a0-9]*[b0-9]*[c0-9]*[d0-9]*[e0-9]*[f0-9]*[- ]+){5}' text.txt
0赞
Ed Morton
10/24/2023
#4
我知道 OP 出于某种原因需要 grep 解决方案,但其他将来阅读此问题时遇到类似问题的人可能没有同样的限制。
记住这句话:
有些人在遇到问题时会想“我知道,我会用 正则表达式。现在他们有两个问题。
并使用任何 awk:
$ cat tst.awk
{
str = $1
gsub(/[0-9]+/,"",str)
numSegs = split(str,segs,"-")
for ( segNr=1; segNr<=numSegs; segNr++ ) {
seg = segs[segNr]
numChars = length(seg)
currChar = substr(seg,1,1)
for ( charNr=2; charNr<=numChars; charNr++ ) {
prevChar = currChar
currChar = substr(seg,charNr,1)
if ( currChar <= prevChar ) {
next
}
}
}
print
}
$ awk -f tst.awk file
a96d7e75-4432-41de-835c-625a636c1914 prefranks
b028224d-314b-4b03-a873-1436838f9233 escape
6cd11113-bcf3-4f73-85f5-145b49225244 neoconservative
96239f18-5c62-495a-b1f8-50759443b885 fellest
51771125-b4d8-4cf8-a3d9-67117263f708 macular
a266f798-d772-47f0-9bdf-451939c2007e buntings
评论
0赞
Walter A
10/24/2023
gsub(/[0-9-]+/,"",str)
应该是gsub(/[0-9]+/,"",str)
0赞
Ed Morton
10/24/2023
@WalterA对了,现在修复了,谢谢。我搞砸了,从 .[^a-f-]
0赞
Walter A
10/24/2023
if ( currChar <= prevChar )
当您接受出现两次的字母时是可以的(恕我直言,这是对问题的正确解释),并且可以简单地更改为当您确实想接受双字母时。这种灵活性说明了 的优点。在我的解决方案中,这个小细节需要一个完全不同的解决方案。if ( currChar < prevChar )
awk
评论
egrep
已被弃用近 20 年,取而代之的是 .grep -E
tar
pax
a96d7e75-4432-41de-835c-625a636c1914 prefranks