代码之家  ›  专栏  ›  技术社区  ›  Olivier Melançon iacob

匹配表示regexp集的模式

  •  2
  • Olivier Melançon iacob  · 技术社区  · 8 年前

    这个问题与可变长度后视无关,因为它可能有一个没有消极后视的解决方案。

    在Python3中,我试图匹配一种模式,这种模式可能已经达到了使用regexp所能达到的极限,但我仍然想尝试一下。我实际上是在试图避免使用解析工具。

    我想要匹配的是指示regexp集的模式。因此,以下内容将匹配。

    [abc]
    [1-9\n\t]
    [ \t\]]
    [\\\]]
    [[\\\\\\\]]
    

    方括号不能嵌套,例如 [[]] ,我们要匹配 [[] .

    虽然,由于 \] 指示转义括号,我们需要跳过这些括号。但模式如下 \\] 必须接受。以下内容不匹配。

    [\]
    [\\\]
    [abc\\\]
    

    规则最终与 [ 到第一个 ] 之前没有奇数的 \ .

    因为必须有固定的长度,所以负向后看似乎不起作用。

    编辑 :Wiktor Stribiżew给出了一个有趣的解决方案

    re.compile(r'\[[^]\\]*(?:\\.[^]\\]*)*\]')
    

    编辑 :通过绘制上述内容的更简单版本

    r'\[(?:\\.|[^]\\])*\]'
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Wiktor Stribiżew    8 年前

    您可以使用

    re.compile(r'\[[^]\\]*(?:\\.[^]\\]*)*]', re.DOTALL)
    

    请参见 regex demo .

    细节

    • \[ -a [ 烧焦
    • [^]\\]* -0个或多个字符,而不是 ] \
    • (?: -匹配以下序列的非捕获组的开始:
      • \\. -a \ 字符后跟任意字符
      • [^]\\]* -0个或多个字符,而不是 ] \
    • )* -非捕捉组内的图案重复次数为零或更多
    • ] -a ] 烧焦

    正则表达式遵循 unroll-the-loop principle . 根据输入的不同,它可能会工作很多,甚至比未展开的版本快10多倍, r'\[(?:\\.|[^]\\])*]' ,即基于无限量化的交替组,导致大量冗余回溯步骤。

    请注意,当初始 [ 前面带有反斜杠。在这种情况下,您需要

    r'(?<!\\)(?:\\{2})*(\[[^]\\]*(?:\\.[^]\\]*)*])'
    

    查看此regex演示

    这里的主要区别是 (?<!\\)(?:\\{2})* (?<!\\) 如果当前位置前面有 \ 字符,以及 (?:\\{2})* 匹配0个以上重复的两个文字反斜杠。模式的其余部分用捕获括号括起来,当找到匹配项时,只需访问 match.group(1) 以获得正确的值。