JavaScript正则表达式意外行为

时间:2015-07-02 14:55:12

标签: javascript regex

让我们在JavaScript中使用以下(有点复杂的)正则表达式:

\{\{\s*(?:(?:\:)([\w\$]+))?\#(?:([\w\$\/]+@?)?([\s\S]*?))?(\.([\w\$\/]*))?\s*\}\}

我想知道为什么它匹配整个字符串:

{{:control#}}x{{*>*}}

但不是在以下情况下(#之后添加空格):

{{:control# }}x{{*>*}}

在PHP或Python中,它在两种情况下只匹配第一部分{{: ... }}

我希望JavaScript也只匹配第一部分。是否可以在(?!}})之前没有黑客[\s\S]

此外,性能是JavaScript中这种不同行为的原因,还是仅仅是规范中的错误?

2 个答案:

答案 0 :(得分:3)

您可以使用惰性??量词来在JavaScript中实现相同的行为:

\{\{\s*(?:(?::)([\w$]+))?#(?:([\w$\/]+@?)?([\s\S]*?))??(\.([\w$\/]*))?\s*}}
                                                     ^^  

请参阅demo

来自rexegg.com

  

A??零或一个A,零,如果仍然允许整体模式匹配(懒惰)

这不是错误,并且根据JavaScript遵守的ECMA标准规范是正确的。

(?:([\w$\/]+@?)?([\s\S]*?))?中,我们有一个可选的非捕获组,可以匹配空文本。 JavaScript正则表达式引擎“消耗”可选组中的空文本,以便稍后通过反向引用访问它们。这个问题与Backreferences to Failed Groups密切相关。例如。 ((q)?b\2)将匹配JavaScript中的b,但在Python和PCRE中不匹配。

  

根据ECMA官方标准,对非参与捕获组的反向引用必须成功匹配任何内容,就像对没有捕获任何内容的参与组的反向引用一样。

答案 1 :(得分:0)

此子模式负责行为:

([\w\$\/]+@?)?  // P1

因为它贪婪地匹配,你的整个测试字符串(没有空格)被消耗掉。

正如@stribizhev所建议的那样,对正则表达式的指定部分进行非贪婪匹配的限定,会导致保守匹配。

两个版本都匹配并包括#,因为两个匹配模式都包含此字符,没有任何出现限制。

第二个测试字符串(包括#之后的空格)非贪婪匹配,因为P1与空格不匹配。而是通过随后的子表达式([\s\S]*?)获得matcehd,从而完成匹配。