【问题标题】:Tempered Greedy Token - What is different about placing the dot before the negative lookahead?Tempered Greedy Token - 将点放在负前瞻之前有什么不同?
【发布时间】:2015-09-03 05:34:17
【问题描述】:
<table((?!</table>).)*</table>

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

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

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

有什么区别?

作为参考,我从这里得到了“Tempered Greedy Token”这个词:Tempered Greedy Token Solution

【问题讨论】:

  • 顺便提一下,这种“缓和”的方式效率特别低。
  • 然后.. 弥补了。事实上,这不是正则表达式领域的标准术语。如果我要进行民意调查,我敢打赌 99% 的正则表达式大师会嘲笑它。
  • 嗯,那个网站的作者对我来说似乎是个大师。另外,我认为为模式命名是有帮助的——正则表达式或其他。我只想让大师们笑一笑。顺便说一句,这种模式有更标准的名称吗?
  • 是的。我将其称为 Record Seperator Construct,因为那是它的唯一用途。这是最后的手段,最低效的方式来匹配任何东西。在正则表达式开头使用断言也是如此(绝对不能这样做!!)。
  • 对不起,我会问你同样的问题:你让Record Seperator Construct 起来了吗?我怀疑这比Tempered Greedy Token 更标准。事实上,谷歌给我这个短语的点击率为零。

标签: regex eclipse


【解决方案1】:

一个脾气暴躁的贪婪令牌真的只是意味着:

"匹配,但只达到一点"

你是怎么做的:

你把令牌你不想匹配作为否定的前瞻 (?!notAllowedToMatch) 在点前面. (匹配任何一个 事情),然后你用星号* 重复整个事情

((?!notAllowedToMatch).)*

它是如何工作的:

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

Wiktor's more detailed answer 很好,但我只是认为需要一个更简单的解释。

【讨论】:

    【解决方案2】:

    ((?!&lt;/table&gt;).)* 将检查将要匹配的特定字符不能是字符串&lt;/table&gt; 中的起始字符。如果是,那么它只匹配那个特定的字符。 * 重复相同的零次或多次。

    (.(?!&lt;/table&gt;))* 匹配任何字符,前提是它后面没有&lt;/table&gt;,零次或多次。所以这将匹配除最后一个字符之外的表标签内的所有字符,因为最后一个字符后跟&lt;/table&gt;。以下模式&lt;/table&gt; 断言在匹配结束时必须有一个结束表标记。这会导致匹配失败。

    here

    【讨论】:

    • 我仍在努力理解第一段。好消息是,我理解您对 (.(?!))* 为何失败的解释。编辑:哦,好吧,我想我现在明白了!
    【解决方案3】:

    什么是 Tempered Greedy Token?

    rexegg.com tempered greedy token 引用非常简洁:

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

    就是这样:tempered greedy token 是一种否定字符类,用于字符序列(对于单个字符,参见negated character class)。

    注意回火的贪婪令牌和否定字符类的区别在于前者并不真正匹配除了序列本身之外的文本,而是一个不开始该序列的单个字符。 IE。 (?:(?!abc|xyz).)+ 不会匹配defabc 中的def,但会匹配def bc,因为a 启动了禁止的abc 序列,而bc 匹配不是。

    它包括:

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

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

    消耗部件放置

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

    我们什么时候应该使用缓和的贪婪令牌?

    Rexegg.com 给出了一个想法:

    性能问题

    缓和的贪婪令牌是资源消耗的,因为在每个字符与消耗模式匹配后执行前瞻检查。 Unrolling the loop technique 可以显着提高缓和的贪婪令牌性能。

    说,我们想匹配 abc 1 abc 2 xyz 3 xyz 中的abc 2 xyz。而不是用abc(?:(?!abc|xyz).)*xyz检查abcxyz之间的每个字符,我们可以用[^ax]*跳过所有不是ax的字符,然后匹配所有没有跟在后面的a bc(带有a(?!bc))和所有x后面没有yz(带有x(?!yz)):abc[^ax]*(?:a(?!bc)[^ax]*|x(?!yz)[^ax]*)*xyz

    【讨论】:

    • 这篇文章在 cmets 部分被重新确认后,我决定接受你非常充实的答案。感谢您抽出宝贵时间整理。
    猜你喜欢
    • 1970-01-01
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 2020-07-03
    • 1970-01-01
    相关资源
    最近更新 更多