温和的贪婪令牌 - 将点放在消极的前瞻之前有什么不同

  • 本文关键字:令牌 贪婪 和的 regex eclipse
  • 更新时间 :
  • 英文 :

<table((?!</table>).)*</table>

匹配我所有的表标签。然而

<table(.(?!</table>))*</table>

不。 如果我尝试用文字写出表达,第二个似乎是有意义的,但我无法理解第一个。

有什么区别?

作为参考,我从这里得到了术语"温和贪婪令牌": 回火贪婪令牌解决方案

什么是赘忍贪婪令牌?

rexegg.com 温和的贪婪令牌引用非常简洁:

(?:(?!{END}).)*中,*量词适用于一个点,但它现在是一个回火的点。负前瞻(?!{END})断言当前位置后面的不是字符串{END}。因此,点永远无法匹配 {END} 的左大括号,保证我们不会跳过{END}分隔符。

就是这样:一个温和的贪婪令牌是字符序列的一种否定字符类(参见单个字符的否定字符类)。

注意回火贪婪标记和否定字符类之间的区别在于,前者与序列本身以外的文本并不真正匹配,而是不启动该序列的单个字符。 即 (?:(?!abc|xyz).)+不会匹配defabc中的def,但会匹配defbc,因为a启动了禁止的abc序列,而bc没有。

它包括:

  • (?:...)* - 一个量化的非捕获组(它可能是一个捕获组,但捕获每个单独的字符没有意义)(可以+ *,这取决于是否预期空字符串匹配)
  • (?!...) - 一个负面的前瞻性,实际上对当前位置右侧的值施加了限制
  • . - (或任何(通常是单个)字符)消费模式。

但是,我们总是可以通过在负前瞻中使用交替来进一步缓和令牌(例如 (?!{(?:END|START|MID)}) ) 或将全匹配点替换为否定的字符类(例如 尝试仅匹配标签内的文本时(?:(?!START|END|MID)[^<>]))。

消耗零件放置

请注意,没有提到在前瞻之前放置消耗部分(原始回火贪婪令牌中的点)的结构。Avinash的回答清楚地解释了这部分:(.(?!</table>))*首先匹配任何字符(但没有DOTALL修饰符的换行符),然后检查它是否没有跟</table>导致<table>table</table>中无法匹配e。*消耗部分(.必须放在回火前瞻之后

我们什么时候应该使用脾气暴躁的贪婪令牌?

Rexegg.com 给出了一个想法:

  • 当我们想要匹配分隔符 1 和分隔符 2 之间的文本块,中间没有子字符串 3 时(例如 {START}(?:(?!{(?:MID|RESTART)}).)*?{END}
  • 当我们想要匹配包含特定模式的文本块而不溢出后续块时(例如,而不是像<table>.*?chair.*?</table>那样的懒惰点匹配,我们会使用 <table>(?:(?!chair|</?table>).)*chair(?:(?!<table>).)*</table> 之类的东西)。
  • 当我们想匹配 2 个字符串之间尽可能短的窗口时。当您需要从abc 1 abc 2 xyz获取abc 2 xyz时,延迟匹配将无济于事(请参阅abc.*?xyzabc(?:(?!abc).)*?xyz)。

性能问题

温和的贪婪令牌会消耗资源,因为在与消耗模式匹配的每个字符之后都会执行前瞻检查。展开循环技术可以显着提高温和的贪婪代币性能。

比如说,我们想在 abc 1 abc 2 xyz 3 xyz 中匹配abc 2 xyz。我们可以跳过所有未a[^ax]* x的字符,abc(?:(?!abc|xyz).)*xyz xyz abc然后匹配所有未跟bc(带a(?!bc))的a和所有不跟yz(带x(?!yz))的xabc[^ax]*(?:a(?!bc)[^ax]*|x(?!yz)[^ax]*)*xyz .

((?!</table>).)*将检查要匹配的特定字符一定不是字符串</table>中的起始字符。如果是,则它仅与该特定字符匹配。 *重复相同的零次或多次。

(.(?!</table>))*仅当字符后跟没有</table>、零次或更多次时,才会匹配任何字符。因此,这将匹配表标记中除最后一个字符之外的所有字符,因为最后一个字符后跟 </table> 。以下模式</table>断言在比赛结束时必须有一个结束表标记。这会使匹配失败。

看这里。

一个温和的贪婪令牌实际上只是意味着:

"匹配,但只能达到一定程度"

你怎么做:

您将不想匹配的令牌作为负面展望 (?!notAllowedToMatch)在点.前面(匹配任何一个事情),然后你用星*重复整个事情

((?!notAllowedToMatch).)*

工作原理:

"看,吃一个"一遍又一遍,在输入字符串中一次从左到右移动一个字符,直到看到不允许的序列(或字符串的结尾),此时匹配停止。

Wiktor更详细的回答很好,但我只是认为应该有一个更简单的解释。

最新更新