为什么string.replace(/\W*/g,'_')前置所有字符?

Jud*_*lin 5 javascript regex

我一直在js学习regexp遇到了一个我不理解的情况.

我使用以下正则表达式对replace函数进行了测试:

/\W*/g
Run Code Online (Sandbox Code Playgroud)

并且期望它在字符串的开头前面并继续替换所有非单词字符.

The Number is (123)(234)
Run Code Online (Sandbox Code Playgroud)

会成为:

_The_Number_is__123___234_
Run Code Online (Sandbox Code Playgroud)

这将是字符串的前置,因为它至少有零个实例,然后替换所有非中断空格和非单词字符.

相反,它会在每个字符前面添加并替换所有非字符.

_T_h_e__N_u_m_b_e_r__i_s__1_2_3__2_3_4__
Run Code Online (Sandbox Code Playgroud)

为什么这样做?

lon*_*day 8

问题在于\W*.它表示"0个或更多非单词字符".这意味着空字符串""将匹配,因为它确实是0个非字字符.

因此,正则表达式在字符串中的每个字符之前和结尾处匹配,因此为什么所有替换都已完成.

您想要/\W/g(替换每个单独的非单词字符)或/\W+/g(替换每组连续的非单词字符).

"The Number is (123)(234)".replace(/\W/g, '_')  // "The_Number_is__123__234_"
"The Number is (123)(234)".replace(/\W+/g, '_') // "The_Number_is_123_234_"
Run Code Online (Sandbox Code Playgroud)


Wik*_*żew 5

JS正则表达式引擎将字符串解析为它们之间的字符和位置序列.请参阅下图,其中我用连字符标记了位置:

  -T-h-e- -N-u-m-b-e-r- -i-s- -(-1-2-3-)-(-2-3-4-)-
  |||                                             |
  ||Location between T and h, etc. .............  |
  |1st symbol                                     |
start                     ->                     end
Run Code Online (Sandbox Code Playgroud)

所有这些职位都可以用正则表达式进行分析和匹配.

由于.replace(/\W/g, '_')是正则表达式匹配0和更多(由于量词)非单词字符的所有非重叠事件(由于*修饰符),所以字字符之前的所有位置都匹配.在和之间,有一个使用正则表达式测试的位置,并且由于没有非单词char(是单词char),返回空匹配(因为可以匹配空字符串)..replace(/\W+/g, '_')*+/\W*/gg

所以,你需要用一个替换字符串的开头和每个非字的字符*.天真的方法是使用T.但是,有一个警告:如果一个字符串以非单词字符开头,则不会h在字符串的开头附加任何字符串:

console.log("Hi there.".replace(/\W|^/g, '_'));  // _Hi_there_
console.log(" Hi there.".replace(/\W|^/g, '_')); // _Hi_there_
Run Code Online (Sandbox Code Playgroud)

请注意,此处h在交替时首先出现,在字符串开头匹配时为"wins":空间匹配,然后在下一次匹配迭代时找不到起始位置.

你现在可能认为你可以匹配\W*.看这里:

console.log("Hi there.".replace(/^|\W/g, '_'));  // _Hi_there_
console.log(" Hi there.".replace(/^|\W/g, '_')); // _ Hi_there_
Run Code Online (Sandbox Code Playgroud)

所述_第二结果表示JS的正则表达式引擎如何替换操作期间处理零宽度匹配:一次零宽度匹配(在这里,它是在字符串的开始时的位置)被发现,发生置换,并且.replace(/\W|^/g, '_')属性被递增,因此前进到第一个角色后的位置!这就是为什么第一个空间被保留,不再匹配的原因_.

解决方案是使用不允许零宽度匹配的消费模式:

console.log("Hi there.".replace(/^(\W?)|\W/g, function($0,$1) { return $1 ? "__" : "_"; }));
console.log(" Hi there.".replace(/^(\W?)|\W/g, function($0,$1) { return $1 ? "__" : "_"; }));
Run Code Online (Sandbox Code Playgroud)

  • @ guest271314:看看[什么是正则表达式?](http://rexegg.com/):*"这些文本字符串描述了在文本正文中查找文本或位置的模式.例如,正则表达式匹配字符串foo,正则表达式`[AZ] +:\ d +`匹配字符串片段,如`F:1`和`GO:30`,正则表达式`(?<= [az])(?= [AZ]) `匹配字符串`CamelCase`我们从一个小写字母转变为一个大写字母的位置."*.有在[先来看一个正则表达式引擎的内部工作原理]在此提示(http://www.regular-expressions.info/engine.html). (2认同)