非固定长度的正则表达式负回溯

Posted

技术标签:

【中文标题】非固定长度的正则表达式负回溯【英文标题】:Regular expression negative lookbehind of non-fixed length 【发布时间】:2014-07-28 09:52:05 【问题描述】:

正如document 所说:

这称为否定后向断言。与肯定的后向断言类似,包含的模式必须只匹配一些固定长度的字符串。

所以这会起作用,目的是匹配之外的任何,,但不在内部:

In [188]:

re.compile("(?<!\)\,.").findall('a1,a2,a3,a4,,a6')
Out[188]:
[',a', ',a', ',a', ',']

这将适用于稍微不同的查询:

In [189]:

re.compile("(?<!\a5)\,.").findall('a1,a2,a3,a4,a5,a6')
#or this: re.compile("(?<!\..)\,.").findall('a1,a2,a3,a4,a5,a6')
Out[189]:
[',a', ',a', ',a', ',']
In [190]:

但如果查询是'a1,a2,a3,a4,_some_length_not_known_in_advance,a6',根据文档,以下内容将无法按预期工作:

In [190]:

re.compile("(?<![\.*])\,.").findall('a1,a2,a3,a4,a5,a6')
Out[190]:
[',a', ',a', ',a', ',', ',a']

有什么办法可以做到这一点吗?消极的回顾是错误的方法吗?

这就是lookbehind最初的设计目的(仅匹配某个固定长度的字符串)的任何原因?

【问题讨论】:

【参考方案1】:

有什么办法可以做到这一点?

是的。有一个非常简单的技巧,这种情况和"regex-match a pattern unless..."很相似

这是你的简单正则表达式:

[^]*|(,)

交替的左侧| 匹配完整的 brackets 标记。我们将忽略这些匹配。右边匹配并捕获第 1 组的逗号,我们知道它们是右边的逗号,因为它们没有被左边的表达式匹配。

这是一个执行多个任务的演示,因此您可以选择(参见the demo)底部的输出:

    计算要匹配的逗号(不是大括号之间的逗号) 显示匹配项(逗号...呵呵) 替换正确的逗号。这里我们替换为SplitHere,这样我们就可以执行任务 4... 用逗号分割,并显示分割后的字符串

参考

How to match (or replace) a pattern except in situations s1, s2, s3...

【讨论】:

太棒了,我觉得我走错了路。让我试试看。知道为什么负后视仅适用于固定长度的设计吗? @CTZhu 我添加了一个完整的 Python 程序,它计算正确的逗号、显示它们、替换它们并拆分字符串。 :) 这样就向您展示了如何使用这种技术完成所有主要工作。 @CTZhu Any idea why negative lookbehind only works for fixed length by design? 这实际上取决于您的正则表达式引擎。在 .NET 中,您可以拥有无​​限宽度的后视功能……在 Python 中也是如此!!!但前提是您使用 Matthew Barnett 的替代(而且很棒)regex 模块。至于为什么......当然,灾难性回溯的工作和机会更多,尤其是在过去的小 RAM 时代。 :) 一个老式的解决方法是反转字符串并使用前瞻。 re.compile("[^]*|(,)").findall('a1,a2,a3,a4,a5,a6') 实际上返回一个额外的'': [',', ',', ',', ',', '']。我有机会通过re 摆脱它吗?感谢regex的提示,我会仔细看看。 @CTZhu 既然你喜欢这个技巧,我强烈建议你看看(或留待以后使用)linked question about exclusions in regex patterns,我写得很开心。 :)【参考方案2】:

除了使用 Negative Lookbehind,您可以使用带有平衡大括号的 Negative Lookahead

,(?![^]*\)

例如:

>>> re.findall(r',..(?![^]*\)', 'a1,a2,a3,a4,_some_unknown_length,a5,a6,a7')
[',a2', ',a3', ',a4']

【讨论】:

谢谢!不匹配任何, 后跟[^]*\ 的巧妙方法。

以上是关于非固定长度的正则表达式负回溯的主要内容,如果未能解决你的问题,请参考以下文章

正则进阶之,回溯, (贪婪* 非贪婪+? 独占++)三种匹配量词

防止在正则表达式上回溯以查找非注释行(不以缩进的“#”开头)

固定位置和长度字段的正则表达式

java 正则表达式 如何匹配固定长度的数字

常用正则表达式

15.python正则匹配 元字符转义重复或捕获分组断言:零度断言负向零宽断言贪婪非贪婪引擎选项