代码如下:
'z/yy'.replace(/\/(y|z)|y|z/g, function(name, index) {
console.log(index, name.length);
return name == 'y' || name == 'z' ? 'a' : name;
});
正确输出:a/ya
'z/yy'.replace(/\/(y|z)|\1/g, function(name, index) {
console.log(index, name.length);
return name == 'y' || name == 'z' ? 'a' : name;
});
错误输出:z/yy
请问为什么呢?
黄舟2017-04-10 14:43:29
@皓矾 的console解释的比较清楚了,唯一不同意的地方是|\1不是匹配所有字符串,而是0长空字符。console里可以看出来。
这里/\/(y|z)|\1/是分为两个正则分别匹配的:
1. \/(y|z) 捕获组1是括号中y|z匹配的内容。比如/(y|z)\1/ 匹配yy,zz,但是不匹配yz
2. \1 捕获组1未定义
所以2中的\1不会如你所想的匹配y或z
比较符合你意图的写法可能是
/\/?(y|z)/
PHP中文网2017-04-10 14:43:29
这两个正则是不等价的。
第一个/\/(y|z)|y|z/g
,分解开来是\/(y|z)
或y
或z
。所以,对于字符串z/yy
,第一个字符z
匹配,被替换为a
,/y
符合但不等于y
或z
,所以原样输出为/y
,最后一个z
同理替换为a
。
第二个/\/(y|z)|\1/g
,比较复杂,展开来说。
在此之前,先根据MDN的文档重写下函数,因为题主的参数不太正确:
"z/yy".replace(/\/(y|z)|\1/g, function(matcher, p1, offset, str) {
console.log(matcher, p1, offset, str);
return matcher == 'y' || matcher == 'z' ? 'a' : matcher;
});
其中,matcher
是匹配的子字符串,p1
是捕捉组匹配的子字符串,既(y|z)
捕捉到的,offset
是偏移值,str
是原字符串。
执行结果如下:
// console.log
line1 '' undefined 0
line2 /y y 1
line3 '' undefined 3
line4 '' undefined 4
一步步来,
z/yy
,matcher
为空,未匹配。/yy
,matcher
为/y
,捕捉到y
。但题主的返回值判断的是matacher
与y
和z
的比较,所以原样返回/y
。y
,matcher
为空,未匹配。matcher
为空,未匹配。关键在第三行,对于字符串'y',正则仍然是/\/(y|z)|\1/g
,而不是题主所想的/\/(y|z)|(y|z)/g
,所以不匹配。
顺带研究了下这种|\1
写法的正则,这种写法貌似会匹配任何字符串,甚至空字符串。比如:
/(x)|\1/g.test("fdaf") // return true
甚至:
/(x)|\1/g.test("") return true
所以,最好还是别这样写……