我的任务是找到带有egrep的行,其中第一个单词包含确切地三个相同的字母。我尝试过使用反向引用,但只找到了一种构建模式的方法,该模式可以找到由 3 个或更多相同字符构建的单词:
egrep -i '^[^[:alpha:]]*\<[a-z]*([a-z])[a-z]*(\1[a-z]*){2}\>'
答案1
以下匹配仅包含 3 个相同 [:alpha:] 字符的行开头的任何“单词”:
grep -i '^\([[:alpha:]]\)\1\1\b'
或者,使用 grep 的-E
( --extended-regexp
) 或-P
(又名--perl-regexp
)选项:
grep -iE '^([[:alpha:]])\1\1\b'
grep -iP '^([[:alpha:]])\1\1\b'
它们与 GNU grep 一起使用,并且(版本除外-P
)与 FreeBSD 的 grep 一起使用。它们可能无法与其他版本的 grep 一起使用。
如果你想匹配任意长度的包含以下内容的单词3个或更多在其中的任何位置使用相同的字母字符,这有点困难。你需要使用一个负前瞻,这需要 perl 兼容的正则表达式。
即它不能用grep -E
(又名egrep
,已被已弃用)。
例如:
$ grep -iP '^[[:alpha:]]*([[:alpha:]])((?:(?!\1)[[:alpha:]])*\1){2}[[:alpha:]]*\b' /usr/share/dict/words
Aaliyah
Aaliyah's
Aarau
Aargau
Aaronical
Abadan
Abbottstown
Abbottstown's
Aberdeen
Aberdeen's
...
zoozoo
zoozoos
zuzzes
zwitterionic
zygogeneses
zygomorphous
zymogeneses
zyzzyva
zyzzyvas
zzz
(根据wc -l
,这与我的 /usr/share/dict/words 文件中的 344817 个单词中的 67117 个匹配)
最后,仅匹配单词正好 3其中任意位置具有相同的 [:alpha:] 字符:
$ grep -iP '^[[:alpha:]]*([[:alpha:]])((?:(?!\1)[[:alpha:]])*\1){2}[[:alpha:]]*\b' /usr/share/dict/words |
grep -viP '^[[:alpha:]]*([[:alpha:]])((?:(?!\1)[[:alpha:]])*\1){3}'
第一个 grep 查找具有 3 个或更多相同字符的单词,第二个 grep 排除具有 4 个或更多相同字符的单词。
我不确定这是否可以用单个正则表达式来完成。
(这与我的 /usr/share/dict/words 文件中的 56820 个单词匹配)。
答案2
我认为您无法使用grep
正则表达式来做到这一点,即使使用 Perl/PCRE 功能(例如零长度断言和反向引用)也是如此。
这很可能是一些理论上的兔子洞,但我对这些东西不感兴趣。
所以就用perl 来做吧。 “算法”可以很容易地翻译成 awk、ruby、python 等:
perl -CiI -anle 'my ($i,%l); ($n=++$l{$_})==3 ? $i++ : $n==4 ? $i-- : () for $F[0]=~/\pL/g; print if $i' file
这可以很容易地进行调整。例如,如果您想查找 3 个字母重复 3 次的单词:
perl -CiI -anle 'my ($i,%l); ($n=++$l{$_})==3 ? $i++ : $n==4 ? $i-- : () for $F[0]=~/\pL/g; print if $i >= 3' /usr/share/dict/words
...
entertainment
...
totalitarianism
或 7 个字母重复 2 次:
perl -CiI -anle 'my ($i,%l); ($n=++$l{$_})==2 ? $i++ : $n==3 ? $i-- : () for $F[0]=~/\pL/g; print if $i >= 7' /usr/share/dict/words
...
electroencephalograph
...
telecommunication
您还可以更改\pL
为仅.
匹配任何字母、$F[0]=~/../
仅/../
或不-a
切换以匹配整行、省略-CiI
仅考虑 ascii 字母等。
答案3
有不仅使用 ERE(扩展正则表达式)构建此类正则表达式的方法。
与 GNU grep (perl regex) (匹配 3 个或更多重复字符)更接近的是:
grep -P '(\w)(((?!\1)\w)*\1){2}' filename
因此,删除重复 4 次或以上的单词,您将得到答案:
grep -P '(\w)(((?!\1)\w)*\1){2}' filename |
grep -Pv '(\w)(((?!\1)\w)*\1){3}'
GNU awk 的替代方案是:
awk '{
a=$1;
while (length(a)){
b=gensub(substr(a,0,1),"","g",a);
if(length(a)-length(b)==3){print $0;next};
a=b
}
}' filename
它的工作原理是删除第一个字符的所有重复,如果删除的是 3 个字符,则打印它,否则,删除下一个第一个字母,直到没有更多的字符可以替换(改进是仅测试剩余长度是否相等或大于所需的重复次数)。
假设您想要计数A
为相当于a
,然后使用以下方法过滤您的文件:
cat /usr/share/dict/words | tr [[:upper:]] [[:lower:]] > words
这两个解决方案相似但不相等。两者在independence
单词上有所不同,例如上面生成的词典文件。
是的,independence
包含 3n
但包含 4 e
。根据首先找到的单词,可能会包含或不包含该单词。 awk 解决方案是稳定的,并且将包含以下单词:任何字符恰好重复 3 次。正则表达式解决方案更加灵活,并且在某些条件下会匹配,而在其他条件下则不匹配。
此外,正则表达式将仅匹配单词不包含的字符'
(并且文件包含多个带有该字符的单词)。
总之,匹配的行数为(使用 awk 则多出 1527 行):
13758 awklist
12231 greplist
并且,删除'
(使用 awk 还可以删除 184 个):
9236 awklist2
9052 greplist2
应该tastelessness teleconferencing teletypewriter teletypewriters tempestuousness timelessness tintinnabulation tintinnabulations tirelessness transcontinental transgressors transubstantiation
(仅列出一些)被拒绝吗?
都确实有3一个字符和四个(或更多)另一个字符。