【问题标题】: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最初的设计目的(仅匹配某个固定长度的字符串)的任何原因?

【问题讨论】:

    标签: python regex python-2.7


    【解决方案1】:

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

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

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

    {[^}]*}|(,)
    

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

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

    1. 计算要匹配的逗号(不是大括号之间的逗号)
    2. 显示匹配项(逗号...呵呵)
    3. 替换正确的逗号。这里我们替换为SplitHere,这样我们就可以执行任务 4...
    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']
    

    【讨论】:

    • 谢谢!不匹配任何, 后跟[^{]*\} 的巧妙方法。
    猜你喜欢
    • 2012-12-06
    • 1970-01-01
    • 2022-09-23
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多