正则表达式 - 嵌套的前瞻断言

4
假设我们想要匹配此文本中所有在<out>...</out>之间的one(选项:点匹配所有):
<out>hello!</out>
<nx1>home one</nx1>
<nx2>living</nx2>
<out>one text
text one continues 
and at last here ends one</out>
<m2>dog one</m2>
<out>bye!</out>

假设我们使用这种模式:

one(?=(?:(?!<out>).)*</out>)

如果有人能够逐步解释正则表达式引擎如何处理该模式以及处理每个阶段的位置(比如像@Tim Pietzcker针对此问题所提供的有用解释:正则表达式 - 向前断言),我会非常感激。


提供的模式将无法匹配out标签之间的所有“one”。例如,第三行包含多个“one”。 - Dhrubajyoti Gogoi
2个回答

5

许多 工具 可以自动解释您的正则表达式每个字符所代表的含义。

然而,其背后的思想是:您希望检查是否跟随着</out>,同时禁止进入新的<out>标签:如果有一个...</out>紧随其后,并且我们没有进入新的<out>...</out>结构,则说明我们已经在其中了。

因此,如果在两者之间没有<out>,并且后面跟着</out>,则正则表达式将匹配one

工作由(?:(?!<out>).)*完成:只有当.不是<out>中第一个<时才进行匹配。因此,我们只能通过消耗不是这个<后跟着out>的字符来到达</out>


提高速度的方法是:

one(?=(?:[^<]*+|<(?!out>))*+</out>)

在每个字符内部进入负向先行搜索会大大增加匹配该字符的成本。这里的[^<]*+将直接匹配到下一个可疑的<,并且我们只在必要时执行负向先行搜索检查。


感谢您的回复;我不明白(?:(?!<out>).)*.*的作用;因此引擎从当前位置(即one之后(第4行))检查5个字符(<out>的长度),看到它并不是该字符串(它是“ text”),那么现在的.是换行符吗? - wiki
@wiki: 别忘了,向前查看是零宽度的,不会消耗字符!(?!<out>).abc上将匹配a:我们从第一个字符后面开始,(?!<out>)检查前5个字符是否为<out>。没有,所以正则表达式继续(我们仍然在a之前),.匹配a。当使用*重复模式时,正则表达式在匹配每个字符之前执行前瞻检查。清楚了吗? - Robin

1
这里是从这里获取的解释:
NODE                     EXPLANATION
--------------------------------------------------------------------------------
  one                      'one'
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    (?:                      group, but do not capture (0 or more
                             times (matching the most amount
                             possible)):
--------------------------------------------------------------------------------
      (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
        <out>                    '<out>'
--------------------------------------------------------------------------------
      )                        end of look-ahead
--------------------------------------------------------------------------------
      .                        any character except \n
--------------------------------------------------------------------------------
    )*                       end of grouping
--------------------------------------------------------------------------------
    </out>                   '</out>'
--------------------------------------------------------------------------------
  )                        end of look-ahead

1
谢谢,但是RegexBuddy可以做得比那个更好!我知道(?!是一个负向前瞻断言!但我想知道的是它在上述模式中的功能;请查看@Tim Pietzcker的解释。 - wiki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接