![](/img/trans.png)
[英]string.replace(fromCharCode() , '') cannot replace characters
[英]Why does string.replace(/\W*/g,'_') prepend all characters?
我一直在学习 js 中的 regexp 遇到了一个我不明白的情况。
我使用以下正则表达式对替换函数进行了测试:
/\W*/g
并期望它在字符串的开头加上并继续替换所有非单词字符。
The Number is (123)(234)
会成为:
_The_Number_is__123___234_
这将是在字符串之前,因为它至少有零个实例,然后替换所有不间断空格和非单词字符。
相反,它在每个字符之前加上并替换了所有非单词字符。
_T_h_e__N_u_m_b_e_r__i_s__1_2_3__2_3_4__
为什么这样做?
问题是\\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_"
TL; 博士
如果您的目标是替换而不是插入文本,则切勿在正则表达式替换方法中使用可以匹配空字符串的模式
要替换字符串中所有单独出现的非单词字符,请使用
.replace(/\\W/g, '_')
(即删除匹配零次或多次出现的量化子模式的*
量词)要将字符串中的所有非单词字符块替换为单个模式,请使用
.replace(/\\W+/g, '_')
(即,将*
量词替换为+
匹配一个或多个出现的量化子模式)
注意:下面的解决方案是为 OP 更具体的要求量身定制的。
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
所有这些位置都可以用正则表达式进行分析和匹配。
由于/\\W*/g
是匹配所有非重叠出现(由于g
修饰符)的0 和更多(由于*
量词)非单词字符的正则表达式,因此匹配单词字符之前的所有位置。 在T
和h
,有一个使用正则表达式测试的位置,并且由于没有非字字符( h
是字字符),因此返回空匹配(因为\\W*
可以匹配空字符串)。
因此,您需要用_
替换字符串的开头和每个非单词字符。 天真的方法是使用.replace(/\\W|^/g, '_')
。 但是,有一个警告:如果字符串以非单词字符开头,则不会在字符串的开头附加_
:
console.log("Hi there.".replace(/\\W|^/g, '_')); // _Hi_there_ console.log(" Hi there.".replace(/\\W|^/g, '_')); // _Hi_there_
请注意,此处\\W
在交替中首先出现,并且在字符串开头匹配时“获胜”:匹配空格,然后在下一次匹配迭代中找不到起始位置。
您现在可能认为您可以匹配/^|\\W/g
。 看这里:
console.log("Hi there.".replace(/^|\\W/g, '_')); // _Hi_there_ console.log(" Hi there.".replace(/^|\\W/g, '_')); // _ Hi_there_
_ Hi_there_
第二个结果显示了 JS 正则表达式引擎如何在替换操作期间处理零宽度匹配:一旦找到零宽度匹配(这里是字符串开头的位置),就会发生替换,并且RegExp.lastIndex
属性递增,从而进行到第一个字符之后的位置! 这就是为什么第一个空格被保留,不再与\\W
匹配的原因。
一种解决方案是使用不允许零宽度匹配的消费模式:
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 ? "__" : "_"; }));
您可以使用RegExp
/(^\\W*){1}|\\W(?!=\\w)/g
匹配一个\\W
在字符串的开头或\\W
不跟\\w
var str = "The Number is (123)(234)"; var res = str.replace(/(^\\W*){1}|\\W(?!=\\w)/g, "_"); console.log(res);
您应该使用 /\\W+/g 代替。
“*”表示所有字符本身。
这是因为您正在使用*
运算符。 匹配零个或多个字符。 所以每个字符之间都匹配。 如果您用/\\W+/g
替换表达式,它会按您的预期工作。
这应该适合你
查找: (?=.)(?:^\\W|\\W$|\\W|^|(.)$)
替换: $1_
案例说明:
(?= . ) # Must be at least 1 char
(?: # Ordered Cases:
^ \W # BOS + non-word (consumes bos)
| \W $ # Non-word + EOS (consumes eos)
| \W # Non-word
| ^ # BOS
| ( . ) # (1), Any char + EOS
$
)
请注意,这可以在没有前瞻的情况下完成(?:^\\W|\\W$|\\W|^$)
但是,这将在空字符串上插入一个_
。
所以,它最终变得更加精细。
总而言之,这是一个简单的替代品。
与 Stribnez 的解决方案不同,不需要回调逻辑
在更换方面。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.