Tempered Greedy Token – 在负面预测之前放置点有什么不同
<table((?!</table>).)*</table>
匹配我所有的表标签,但是,
<table(.(?!</table>))*</table>
才不是。 第二个似乎是有道理的,如果我试图用文字写出expression,但我不能理解第一个。
有人可以向我解释这个区别吗?
作为参考,我从这里得到了“Tempered Greedy Token”这个词: http : //www.rexegg.com/regex-quantifiers.html#tempered_greed
由于Google在tempered greedy token
的结果中回报了这个问题,所以我觉得有必要提供一个更全面的答案。
什么是脾气暴躁的令牌?
rexegg.com 脾气贪婪的标记引用是相当简洁的:
在
(?:(?!{END}).)*
,*
量词适用于一个点,但现在是一个回火点。 负向前瞻(?!{END})
声明跟在当前位置之后的不是string{END}
。 因此,点不能匹配{END}
的开始大括号,保证我们不会跳过{END}
分隔符。
那就是: 脾气暴躁的标记是一种字符序列的 否定字符类 (比较单个字符的 否定字符类 )。
注意 : 脾气暴躁的标记和否定的字符类之间的区别在于 ,前者与序列本身以外的文本并不真正匹配,而是单个字符不会启动该序列。 即(?:(?!abc|xyz).)+
在defabc
不会与def
相defabc
,但会匹配def
和 bc
,因为a
启动被禁止的abc
序列,而bc
不会。
它包括:
-
(?:...)*
– 一个量化的非捕获组(它可能是一个捕获组,但是捕获每个单独的字符是没有意义的)(a*
可以是+
,这取决于空string匹配是预期) -
(?!...)
– 实际上对当前位置右侧的值施加限制的负向预测 -
.
– (或任何(通常是单个)字符)消费模式。
然而,我们总是可以通过使用反向预测(例如(?!{(?:END|START|MID)})
)中的交替或通过用否定的字符类replace全匹配的点来进一步调节令牌(例如(?:(?!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个string之间可能的最短窗口。 当你需要得到
abc 2 xyz
时,懒惰的匹配将无济于事abc 2 xyz
abc 1 abc 2 xyz
(见abc.*?xyz
和abc(?:(?!abc).)*?xyz
)。
性能问题
贪婪的贪婪标记是耗费资源的,因为在每个与消费模式匹配的字符之后执行预先检查。 展开循环技术可以显着提高贪婪的贪婪标记性能。
比方说,我们想在abc 1 abc 2 xyz 3 xyz中匹配abc 2 xyz
xyz 。 而不是使用abc(?:(?!abc|xyz).)*xyz
检查abc
和xyz
之间的每个字符abc(?:(?!abc|xyz).)*xyz
,我们可以用[^ax]*
跳过所有不是a
或x
字符,然后匹配所有没有跟随bc
(带有a(?!bc)
)和所有没有跟随yz
(带有x(?!yz)
)的x(?!yz)
: abc[^ax]*(?:a(?!bc)[^ax]*|x(?!yz)[^ax]*)*xyz
。
((?!</table>).)*
将检查要匹配的特定字符不能是string</table>
的起始字符。 如果是,那么只有它匹配那个特定的字符。 *
重复相同的零次或多次。
(.(?!</table>))*
只有在没有</table>
才会匹配任何字符,零次或多次。 所以这将匹配表标签内的所有字符excpet最后一个字符,因为最后一个字符后面是</table>
。 下面的模式</table>
声明在比赛结束时必须有一个closures表格标签。 这使比赛失败。
看到这里
温和的贪婪标记实际上意味着:
“匹配,但只能达到一个点”
你如何做到这一点:
你把你不想匹配的标记作为一个负面的前瞻
(?!notAllowedToMatch)
在一个点的前面.
(匹配任何一件事),那么你重复整个事情与星*
:
((?!notAllowedToMatch).)*
怎么运行的:
“看,吃”一遍又一遍,通过inputstring从左到右移动一个字符 ,直到看到不允许的序列(或string的结束),此时匹配停止。
Wiktor的更详细的答案是好的,我只是想一个简单的解释是为了。