繁体   English   中英

sed和python正则表达式之间的不一致

[英]Inconsistency between sed and python regular expressions

如果这是在某个地方发布我道歉,但我粗略的搜索没有发现任何东西。

在做一些Python编程时,我注意到以下命令:

re.sub("a*((ab)*)b", r"\1", "aabb")

返回空字符串。 但是sed中的等效命令:

echo "aabb" | sed "s/a*\(\(ab\)*\)b/\1/"

返回ab

这是有道理的,我认为在“a *”指令在蟒蛇正则表达式的开始将同时匹配a的,造成‘(AB)*’匹配零次,但我不知道如何SED与出现ab 有谁知道造成这种情况的两个正则表达式引擎之间有什么区别? 我相信它们都默认贪婪地匹配星星,但我发现sed可能从右边而不是左边匹配。 任何见解将不胜感激。

默认情况下Python和sed都是贪婪的但是...... Python正则表达式尝试在所有情况下从左到右进行评估,尽管如果正在尝试的分支无法通过匹配继续,它必须最终回溯到之前的状态。 相反,在评估之前优化Sed正则表达式,以便通过将正则表达式重写为更确定的形式来防止不必要的回溯。 因此,组合的可选模式“aab”可能在普通“a”之前进行测试,因为首先尝试了最具体的可能字符串。

Python模式将字符串“aabb”两次匹配为“aab”+“b”(标记在“<>”之间)

>>> re.sub("a*((ab)*)b", r"<\1>", "aabb")
'<><>'

而sed通过一次替换匹配整个“aabb”:

$ echo "aabb" | sed "s/a*\(\(ab\)*\)b/<\1>/"
<ab>

Python正则表达式回溯算法在正则表达式中得到了很好的解释-在“一步一步的例子......”中引入的两段中重复事物 IMO完全按照正则表达式文档描述:“当扫描目标字符串时,RE由'|'分隔 从左到右尝试 。“

示范

“(| a | aa)”btw的顺序。 “(aa | a |)”受到Python的尊重

>>> re.sub("(?:|a|aa)((ab)*)b", r"<\1>", "aabb")
'<ab>'
>>> re.sub("(?:aa|a|)((ab)*)b", r"<\1>", "aabb")
'<><>'

但是这个顺序被sed忽略,因为sed优化了正则表达式。 匹配“aab”+“b”可以从模式中删除“a”选项。

$ echo "aabb" | sed "s/\(\|a\|aa\)\(\(ab\)*\)b/<\2>/g"
<ab>
$ echo "aabb" | sed "s/\(aa\|a\|\)\(\(ab\)*\)b/<\2>/g"
<ab>
$ echo "aabb" | sed "s/\(aa\|\)\(\(ab\)*\)b/<\2>/g"
<><>

编辑 :我删除了有关DFA / NFA的所有内容,因为我无法从当前文本中证明这一点。

你构建的有趣的谜题。 从我读过的文章来看,python和sed的regexp引擎都基于Henry Spencer的正则表达式库(就像perl一样),它依赖于回溯。 (不幸的是我找不到我正在基于此的文章)。

无论如何,这不是一个应该是实现细节的东西:Python的行为违背了POSIX标准,它要求RE(a)尽可能匹配,(b)匹配从那个点开始的最长字符串。 (请参阅man 7 regex (在Linux上)以及更多内容。)

要找到最长的匹配项,回溯(“NFA类型”)正则表达式引擎必须在找到一个匹配项后继续检查备选项。 因此,实施者偷工减料也就不足为奇了。 显然,python的行为是不符合的,因为它找不到最长的匹配。 根据sed手册页,sed并不总是符合“出于性能原因”。 但显然这种情况是正确的。

顺便说一下,你的命令并不完全等价: re.sub会尽可能多地执行替换,而sed的s/a/b/只会执行一次.sed版本应该是:

echo "aabb" | sed "s/a*\(\(ab\)*\)b/\1/g"

这解释了为什么我们在python中得到空字符串:RE第一次匹配aab ,第二次匹配剩余的b ,删除每个部分(因为它全部匹配a*和正则表达式的最后一个b )。 您可以通过以下变体看到此信息:

>>> re.sub("a*((ab)*)b", r"X\1Y", "aabb")
'XYXY'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM