ERE - 将量词添加到具有内部组和反向引用的组

时间:2017-04-23 15:19:46

标签: regex sed grep gnu pcre

试图连续重复的字母出现两次或三次。无法找到使用ERE

使用量词和捕获组的方法
$ grep --version | head -n1
grep (GNU grep) 2.25

$ # consecutive repeated letters occurring twice
$ grep -m5 -xiE '[a-z]*([a-z])\1[a-z]*[a-z]*([a-z])\2[a-z]*' /usr/share/dict/words
Abbott
Annabelle
Annette
Appaloosa
Appleseed

$ # no output for this, why?
$ grep -m5 -xiE '([a-z]*([a-z])\2[a-z]*){2}' /usr/share/dict/words


适用于-P

$ grep -m5 -xiP '([a-z]*([a-z])\2[a-z]*){2}' /usr/share/dict/words
Abbott
Annabelle
Annette
Appaloosa
Appleseed

$ grep -m5 -xiP '([a-z]*([a-z])\2[a-z]*){3}' /usr/share/dict/words
Chattahoochee
McConnell
Mississippi
Mississippian
Mississippians


感谢Casimir et Hippolyte提出更简单的输入和正则表达式来测试此行为

$ echo 'aazbb' | grep -E '(([a-z])\2[a-z]*){2}' || echo 'No match'
aazbb
$ echo 'aazbbycc' | grep -E '(([a-z])\2[a-z]*){2}([a-z])\3[a-z]*' || echo 'No match'
aazbbycc
$ echo 'aazbbycc' | grep -P '(([a-z])\2[a-z]*){3}' || echo 'No match'
aazbbycc

$ # failing case
$ echo 'aazbbycc' | grep -E '(([a-z])\2[a-z]*){3}' || echo 'No match'
No match

sed同样的行为

$ sed --version | head -n1
sed (GNU sed) 4.2.2

$ echo 'aazbb' | sed -E '/(([a-z])\2[a-z]*){2}/! s/.*/No match/'
aazbb    
$ echo 'aazbbycc' | sed -E '/(([a-z])\2[a-z]*){2}([a-z])\3[a-z]*/! s/.*/No match/'
aazbbycc

$ # failing case
$ echo 'aazbbycc' | sed -E '/(([a-z])\2[a-z]*){3}/! s/.*/No match/'
No match


相关搜索链接,我检查了其中一些,但没有得到任何接近这个问题

如果在较新版本的grepsed中解决此问题,请与我们联系。此外,如果在非GNU实现中看到问题

4 个答案:

答案 0 :(得分:2)

我认为-E不允许Quantifiers,这就是为什么它仅适用于-P

匹配2个或更多连续的重复字母组:

grep -P '(?:([a-z])\1*([a-z])\2){1}' /usr/share/dict/words

匹配3个或更多连续的重复字母组:

grep -P '(?:([a-z])\1*([a-z])\2){2}' /usr/share/dict/words

选项:

-P, --perl-regexp         PATTERN is a Perl regular expression

答案 1 :(得分:0)

更新

搜索完之后,我在我的windows box上安装了gnugrep32,然后运行了
一些测试:

我是从旧的SO帖子中读到的:

  

非贪婪匹配不是grep

支持的扩展正则表达式语法的一部分

因此,我们使用[a-z]{0,20}作为测试,而不是[a-z]*[a-z]*?,其中?被忽略(wtf?)

以下是使用整体(){n}的增量测试,以了解 STOPS BACKTRACKING 之前的距离 进入帧。

最近工作

(([a-z])\2[a-z]{0,20}){1}   len = 2    rr
(([a-z])\2[a-z]{0,20}){2}   len = 4    rrrr
(([a-z])\2[a-z]{0,20}){3}   len = 25   rrrrrrrrrrrrrrrrrrrrrrrrr
(([a-z])\2[a-z]{0,20}){4}   len = 47   rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
(([a-z])\2[a-z]{0,20}){5}   len = 69   rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
(([a-z])\2[a-z]{0,20}){6}   len = 91   rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr

{3}{6},delta长度等于22.

这恰好是捕获帧表达式([a-z])\2[a-z]{0,20}的全长 当它没有回溯到之前的帧时。

结论是它会在2帧后自动停止回溯。

例如,在20帧中,它变为16,并且发现它无法匹配。 然后它回到第1帧并在那里进行调整并在agaqin上尝试。

为什么会这样。
然而,它现在已经消耗了大量的记忆,臃肿的猪必须放松它 这可能需要永远使用这个旧的古老的实用程序 嘿,最好把它限制在2帧。

当然,由于贪婪量词(([a-z])\2[a-z]*){3}*没有测试用例 如果它们都是[a-z],则会消耗第二帧上的整行,甚至从不使用 开始第三帧。

答案 2 :(得分:0)

$ # no output for this, why?
$ grep -m5 -xiE '([a-z]*([a-z])\2[a-z]*){2}' /usr/share/dict/words

因为您搜索内部具有(至少)双字母的双组(两次相同)。类似于abbcabbc [(...) = "abbc" 2次]而不是2(最终类似)的内容,其中每个内部都有一个双字母,如abbcdeef

有2个后退参考:

$ grep -iE '[a-z]*([a-z])\1{1,}[a-z]*([a-z])\2{1,}[a-z]*`

答案 3 :(得分:0)

我提交了一个问题 https://debbugs.gnu.org/cgi/bugreport.cgi?bug=26864,现在更新了手册以反映此类问题。

来自https://www.gnu.org/software/grep/manual/grep.html#Known-Bugs

<块引用>

反向引用会大大减慢匹配速度,因为它们会产生成倍数的匹配可能性,这会消耗时间和内存进行探索。此外,反向引用的 POSIX 规范有时也不清楚。此外,许多正则表达式实现都存在反向引用错误,这些错误可能导致程序返回错误答案甚至崩溃,而修复这些错误的优先级通常较低:例如,截至 2020 年,GNU C library bug database 包含反向引用错误 5210844110532426925322,几乎没有即将修复的迹象。幸运的是,反向引用很少有用,在实际应用中避免它们应该不难。