让我们在JavaScript中使用以下(有点复杂的)正则表达式:
\{\{\s*(?:(?:\:)([\w\$]+))?\#(?:([\w\$\/]+@?)?([\s\S]*?))?(\.([\w\$\/]*))?\s*\}\}
我想知道为什么它匹配整个字符串:
{{:control#}}x{{*>*}}
但不是在以下情况下(#
之后添加空格):
{{:control# }}x{{*>*}}
在PHP或Python中,它在两种情况下只匹配第一部分{{: ... }}
。
我希望JavaScript也只匹配第一部分。是否可以在(?!}})
之前没有黑客[\s\S]
?
此外,性能是JavaScript中这种不同行为的原因,还是仅仅是规范中的错误?
答案 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,从而完成匹配。