Tempered Greedy Token - 在负前瞻之前放置点有什么不同

jra*_*ali 16 regex eclipse

<table((?!</table>).)*</table>
Run Code Online (Sandbox Code Playgroud)

但是,匹配我的所有表格标签

<table(.(?!</table>))*</table>
Run Code Online (Sandbox Code Playgroud)

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

有人可以向我解释一下这个区别吗?

作为参考,我从这里得到了"Tempered Greedy Token"这个术语:http://www.rexegg.com/regex-quantifiers.html#tempered_greed

Wik*_*żew 38

由于谷歌在结果的基础上回复了这个问题tempered greedy token,我觉得有必要提供更全面的答案.

什么是淬火贪婪令牌?

rexegg.com 调和贪婪的令牌参考非常简洁:

(?:(?!{END}).)*,*量词适用于点,但它现在是一个回火点.负向前瞻(?!{END})断言当前位置后面的内容不是字符串{END}.因此,点永远不能匹配开口支撑{END},保证我们不会跳过{END}分隔符.

这就是它:一个脾气贪婪令牌是一个样的否定字符类的字符序列(参见否定字符类单个字符).

注意:调和贪婪令牌和否定字符类之间区别在于前者与序列本身以外的文本不匹配,而是与单个字符不能启动该序列.即(?:(?!abc|xyz).)+不匹配defdefabc,但将匹配def bc,因为a开始禁止abc序列,并bc没有.

它包括:

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

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

消费部分安置

注意,没有提到一种结构,其中消耗部分(原始淬火贪婪标记中的点)放置前瞻之前.阿维纳什的答案显然是解释部分:(.(?!</table>))*第一匹配任何字符(但换行而不建立DOTALL修改),然后如果它并没有随着检查</table>导致的不匹配e<table>table</table>.消耗部件(.)必须放在回火先行之后.

什么时候使用淬火贪婪令牌?

Rexegg.com提出了一个想法:

绩效问题

由于在每个字符与消费模式匹配之后执行先行检查,因此驯化贪婪令牌是消耗资源的.展开循环技术可以显着提高驯化贪婪令牌的性能.

说,我们想要abc 2 xyzabc 1 abc 2 xyz 3 xyz中匹配.相反,检查之间的每个字符abc,并xyzabc(?:(?!abc|xyz).)*xyz,我们可以跳过这是不是所有的字符,ax[^ax]*,然后匹配所有a未注视着bc(带a(?!bc))和所有x未遵循与yz(含x(?!yz))abc[^ax]*(?:a(?!bc)[^ax]*|x(?!yz)[^ax]*)*xyz.

  • 在评论部分重新发布此帖后,我决定接受你非常充实的答案.感谢您抽出宝贵时间将它们整合在一起. (2认同)

Avi*_*Raj 9

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

(.(?!</table>))*只有在没有跟随</table>,零次或多次的情况下才匹配任何字符.因此,这将匹配表标记内的所有字符,从而删除最后一个字符,因为最后一个字符后跟</table>.并且以下模式</table>断言在匹配结束时必须有一个关闭表标记.这使得匹配失败.

看到这里


Sco*_*ver 6

一个脾气暴躁的贪婪令牌实际上意味着:

“匹配,但仅限于一定程度”

你怎么做:

您将不想匹配的标记作为否定前瞻 (?!notAllowedToMatch)放在点前面.(匹配任何一件事),然后用星号重复整个事情*

((?!notAllowedToMatch).)*

怎么运行的:

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

Wiktor 的更详细的答案很好,但我只是认为更简单的解释是合适的。