我有这个JavaScript(在Chrome 48.0.2564.103 m中运行):
var s1 = 'label1="abc" label2=\'def\' ';
var s2 = 'label1="abc" label2=\'def\' label3="ghi"';
var re = /\b(\w+)\b=(['"]).*?def.*?\2/;
re.exec(s1); // --> ["label2='def'", "label2", "'"]
re.exec(s2); // --> ["label1="abc" label2='def' label3="", "label1", """]
第一个exec()匹配label2,正如我所预期的那样。然而,第二个被'label3 ='后的双引号混淆,而是匹配label1。
我曾预料到会使用。*?告诉正则表达式使匹配尽可能紧密,但显然并非总是如此。有没有办法收紧我的正则表达式?
答案 0 :(得分:3)
只要排除被视为引用的内容
/\b(\w+)\b=(['"])(?:.(?!\2))*def(?:.(?!\2))*.?\2/
因此,此更改正在将.*?
替换为(?:.(?!\2))*
。
分解:
(?!)
是负向前看,非捕捉(?:)
是非捕获组。def
,需要.?
来修复这允许您在允许a='\''
或a="\""
或进一步a="\\\""
时合并其他规则:
/\b(\w+)\b=(['"])(?:\\\\|\\\2|.(?!\2))*def(?:\\\\|\\\2|.(?!\2))*.?\2/
答案 1 :(得分:3)
s2
给出不同结果的原因是您在" def"的右侧添加了"
。在label2之后,它允许模式正确匹配字符串中第一个和最后一个双引号之间的所有内容。
我只能猜测稀疏匹配(?
)没有任何影响的原因是,此时正则表达式引擎已经决定匹配"
而不是{{ 1}}。毕竟,正则表达式从左到右完成了它。
最简单的"解决这个问题的方法是在引号之间仅匹配非引号,而不是使用'
:
.
问题在于,现在您无法在值中添加任何类型的引号,即使它们完全合法:
var re = /\b(\w+)\b=(['"])[^'"]*def[^'"]*\2/;
re.exec(s1); // --> ["label2='def'", "label2", "'"]
re.exec(s2); // --> ["label2='def'", "label2", "'"]
但基本上,正则表达式不是用于解析HTML的,所以如果这些限制是一个问题,你应该考虑正确的解析。