【问题标题】:Why doesn't the RegExp "greedy" mode work?为什么 RegExp“贪婪”模式不起作用?
【发布时间】:2025-12-18 05:45:01
【问题描述】:

我不明白这种行为。我有这样的例子,需要捕捉html评论。

var str = '.. <!--My -- comment test--> ';

var regex1 = /<!--[.]*-->/g;
var regex2 = /<!--.*-->/g;

alert(str.match(regex1));      // null
alert(str.match(regex2));      // <!--My -- comment test--> 

第二个正则表达式regex2 工作正常,准确输出所需内容。第一个显示null。而且我不明白其中的区别。正则表达式&lt;!--[.]*--&gt;&lt;!--.*--&gt; 的含义相同-“在&lt;!-- 之后,取除换行符之外的任何字符,数量从0 到尽可能多,并以--&gt; 结尾”。但是对于第二个它有效,而对于第一个则无效。为什么?

UPD。 我已经阅读了 cmets 并且有更新。

var str3 = '.. <!--Mycommenttest--> ';
var str4 = '.. <!--My comment test--> ';

var regex3 = /<!--[\w]*-->/g;
var regex4 = /<!--[\s\S]*-->/g;

alert(str.match(regex3));         // <!--Mycommentstest-->
alert(str.match(regex4));         // <!-- My comment test -->

因此可以使用有限的匹配变量来匹配任何内容。那么应该使用哪种方式正确使用 RegExps 呢?有[] 还是没有它们?无法区分,两者都给出正确的输出。

【问题讨论】:

  • 您知道,“贪婪”匹配意味着您的模式将匹配&lt;!-- Comment --&gt; (Content) &lt;!-- Another Comment --&gt;。我怀疑这不是你想要的。
  • 请注意&lt;!-- foo -- bar --&gt;an invalid HTML/SGML comment

标签: javascript regex regex-greedy quantifiers


【解决方案1】:

点 (.) 并不表示字符类中的“任何东西”。为什么需要一个字符类来匹配任何东西?

【讨论】:

  • 因为您使用的是 JavaScript? ;) 如果没有单行(或“DOTALL”)模式,. 永远不会真正匹配 任何东西,因此您必须使用像 [\s\S] 这样的解决方法。
  • @AlanMoore 有趣的注释。我必须承认这是一个快速而肮脏的答案,得到了太多的支持,我没有花时间说明 anything 的真正含义——除了引用它(有点主观,但试图说除了换行符之外的任何东西。这种 JavaScript 特性对我来说是新事物。感谢您的意见。
  • 是的,这是人生的一大奥秘。鉴于 JS 奇特的开发模式,我可以理解它不支持像lookbehinds 和conditionals 这样的高级功能,而是单行模式?这就像设计一辆可以直行或左转但不能右转的汽车。
【解决方案2】:

\w\d\s 这样的字符类简写表示内部字符类与out 完全相同,但是像. 这样的元字符通常在字符类中失去它们的特殊含义。这就是为什么 /&lt;!--[.]*--&gt;/ 没有按预期工作的原因:[.] 匹配文字 .

但是/&lt;!--.*--&gt;/ 也不起作用,因为. 不匹配换行符。在大多数正则表达式风格中,您将使用单行模式让点匹配所有字符包括换行符,例如:/&lt;!--.*--&gt;/s 或:(?s)&lt;!--.*--&gt;。但是 JavaScript 不支持该功能,因此大多数人使用 [\s\S] 代替,意思是“任何空白字符或任何 空白字符”——换句话说,任何字符。

但这也不对,因为(正如 Jason 在他的评论中指出的那样)它会贪婪地匹配从第一个 &lt;!-- 到最后一个 --&gt; 的所有内容,这可能包含几个单独的 cmets 和所有非评论材料它们之间。让它真正正确可能不值得付出努力。当使用正则表达式匹配 HTML 时,无论如何您都必须做出许多简化假设;如果你不能假设一定程度的良好状态,你还不如放弃。在这种情况下,使量词不贪婪就足够了:

var regex5 = /<!--[\s\S]*?-->/g;

【讨论】:

    【解决方案3】:

    RegExpressions &lt;!--[.]*--&gt;&lt;!--.*--&gt; 意思相同

    这是不正确的。

    括号[] 表示一个字符类,该类中的任何字符都可以匹配。 [.] 是包含“.”字符的字符类。将此与. 进行对比,. 是一个预定义 字符类,意为“任何字符”(行终止符除外)。

    因此,您与 &lt;!--[.]*--&gt; 匹配的是空评论或完全由“.”字符组成的评论。您与&lt;!--.*--&gt; 匹配的内容要么是空注释,要么是由除换行符以外的任何字符填充的注释。

    【讨论】:

      【解决方案4】:

      第一个不是,因为它的意思不同。第一个表示匹配句点字符。当放在 [] 集合中时,句点字符不是通用匹配。 (如果你仔细想想,这是有道理的:你为什么要匹配一组有限匹配变量中的任何东西)

      【讨论】: