奇怪的负面行为向前看

时间:2017-07-11 23:17:38

标签: regex negative-lookahead

我有以下字符串: <div data-sticky-container > <div id="mobileMenu" class="title-bar" data-responsive-toggle="main-menu" data-hide="medium" data-sticky data-options="marginTop:0;" style="width:100%" data-top-anchor="top"> <button class="menu-icon" type="button" data-toggle="main-menu"></button> <div class="title-bar-title">Menu</div> </div> </div> <div data-sticky-container> <div class="top-bar" id="main-menu" data-sticky data-options="marginTop:0;" style="width:100%" data-top-anchor="1"> <div class="top-bar-left"> <ul class="dropdown menu" data-dropdown-menu> <!--links here--> </ul> </div> </div> </div> 。我希望将AB中的文本与第一次出现的CD相匹配。受this回答的启发,我创建了以下正则表达式模式:

"text before AB000CD000CD text after"

我在https://regex101.com/中检查了结果,输出为:

AB((?!CD).)*CD

看起来它能满足我的需求。但是我不明白它为什么会起作用。我的理解是我的模式应首先匹配AB,然后是任何未跟随CD的角色,然后是CD本身。但遵循这个逻辑,结果不应该包括000,而只包括00,因为最后的零实际上是CD。我的解释错了吗?

1 个答案:

答案 0 :(得分:3)

AB((?!CD).)*CD匹配AB,然后匹配任何未启动CD字符序列的字符,然后CD。那就是你错误地说“没有跟着CD”。请注意,负向前瞻位于 .之前

此外,当否定部分与尾部边界相同时使用tempered greedy token是没有意义的,只需使用惰性点匹配模式AB(.*?)CD。如果您不想在ABAB之间匹配CD(初始边界),则需要使用该构造。 AB((?:(?!AB).)*?)CD(这是最常见的用例)。

请参阅rexegg.com reference了解何时使用它:

  

假设我们的老板现在告诉我们,我们仍然希望匹配并包括{END},但我们还需要避免单步执行{MID}部分(如果存在)。从懒惰的点星版本开始,以确保我们匹配{END}分隔符,然后我们可以调整点以确保它不会翻转{MID}

     

{START}(?:(?!{MID}).)*?{END}

     

如果必须避免使用更多短语,我们只需将它们添加到我们的脾气点:

     

{START}(?:(?!{MID})(?!{RESTART}).)*?{END}

另外,see this thread