如何替换 JavaScript 中所有出现的字符串
Posted
技术标签:
【中文标题】如何替换 JavaScript 中所有出现的字符串【英文标题】:How to replace all occurrences of a string in JavaScript 【发布时间】:2022-01-05 07:37:34 【问题描述】:我的 javascript 代码中有这个字符串:
"Test abc test test abc test test test abc test test abc"
在做:
str = str.replace('abc', '');
似乎只删除了上面字符串中第一次出现的abc
。
我怎样才能替换它的所有次出现?
【问题讨论】:
当用ca
替换ababa
中出现的所有aba
时,您期望得到什么结果? caba
? abca
? cca
?
String.prototype.replaceAll()
现在是 ECMAScript tc39.es/ecma262/#sec-string.prototype.replaceall 的标准部分,记录在 developer.mozilla.org/docs/Web/JavaScript/Reference/… 并在 Safari 13.1、Firefox 77 和 Chrome Dev/Canary 中提供,并将在 Chrome 85 中提供。来自文档:“如果 searchValue 是一个字符串,则替换所有出现的 searchValue(就好像 .split(searchValue).join(replaceValue)
或已使用全局和正确转义的正则表达式一样)。如果 searchValue 是非全局正则表达式,则抛出异常”
使用正则表达式而不是字符串,应该看起来像 str.replace(/abc/g, '');
这样 g 来获取所有匹配项。
【参考方案1】:
截至 2020 年 8 月: Modern browsers have support 用于 ECMAScript 2021 语言规范定义的 String.replaceAll()
method。
对于旧版/旧版浏览器:
function escapeRegExp(string)
return string.replace(/[.*+?^$()|[\]\\]/g, '\\$&'); // $& means the whole matched string
function replaceAll(str, find, replace)
return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
这是这个答案的演变过程:
str = str.replace(/abc/g, '');
回应评论“如果'abc'作为变量传递会怎样?”:
var find = 'abc';
var re = new RegExp(find, 'g');
str = str.replace(re, '');
针对Click Upvote的评论,您可以进一步简化:
function replaceAll(str, find, replace)
return str.replace(new RegExp(find, 'g'), replace);
注意:正则表达式包含特殊(元)字符,因此在上面的find
函数中盲目地传递参数而不进行预处理以转义这些字符是很危险的。这在Mozilla Developer Network 的JavaScript Guide on Regular Expressions 中有介绍,其中提供了以下实用功能(自最初编写此答案以来,该功能至少更改了两次,因此请务必检查 MDN 站点以获取潜在更新):
function escapeRegExp(string)
return string.replace(/[.*+?^$()|[\]\\]/g, '\\$&'); // $& means the whole matched string
所以为了让上面的replaceAll()
函数更安全,如果还包含escapeRegExp
,可以修改成如下:
function replaceAll(str, find, replace)
return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
【讨论】:
在escapeRegExp
中,]
和
是额外的(不必转义)。最好是:.replace(/[.^$*+?()[|\\]/g, "\\$&")
【参考方案2】:
为了完整起见,我开始考虑应该使用哪种方法来做到这一点。根据本页其他答案的建议,基本上有两种方法可以做到这一点。
注意:一般来说,不建议在 JavaScript 中扩展内置原型。我提供作为 String 原型的扩展只是为了说明,在 String
内置原型上显示假设标准方法的不同实现。
基于正则表达式的实现
String.prototype.replaceAll = function(search, replacement)
var target = this;
return target.replace(new RegExp(search, 'g'), replacement);
;
拆分和连接(功能)实现
String.prototype.replaceAll = function(search, replacement)
var target = this;
return target.split(search).join(replacement);
;
我不太了解正则表达式在效率方面是如何在幕后工作的,过去我倾向于倾向于 split 和 join 实现而不考虑性能。当我确实想知道哪个更有效率,以及有多大的差距时,我用它作为找出答案的借口。
在我的 Chrome Windows 8 机器上,基于正则表达式的实现最快,拆分和连接实现慢 53%。这意味着对于我使用的 lorem ipsum 输入,正则表达式的速度是原来的两倍。
查看此benchmark 运行这两个实现相互对抗。
正如@ThomasLeduc 和其他人在下面的评论中所指出的,如果search
包含某些保留为special characters in regular expressions 的字符,则基于正则表达式的实现可能会出现问题。该实现假定调用者将预先转义字符串或仅传递 Regular Expressions (MDN) 中的表中没有字符的字符串。
MDN 还提供了一个实现来转义我们的字符串。如果这也被标准化为RegExp.escape(str)
,那就太好了,但是唉,它不存在:
function escapeRegExp(str)
return str.replace(/[.*+?^$()|[\]\\]/g, "\\$&"); // $& means the whole matched string
我们可以在String.prototype.replaceAll
实现中调用escapeRegExp
,但是,我不确定这会对性能产生多大影响(甚至可能对于不需要转义的字符串,如所有字母数字字符串)。
【讨论】:
2021年String.prototype.replaceAll()原生存在。所以这个实现应该在使用前先检查一下。 m 使用nestjs,所以打字稿显示replaceAll不是String原型的方法的错误,有什么解决方案吗?【参考方案3】:更新:在大多数流行浏览器的最新版本中,您可以使用replaceAll
如图所示:
let result = "1 abc 2 abc 3".replaceAll("abc", "xyz");
// `result` is "1 xyz 2 xyz 3"
但请先检查Can I use 或其他兼容性表,以确保您的目标浏览器首先添加了对它的支持。
对于 Node 以及与旧版/非当前浏览器的兼容性:
注意:请勿在性能关键代码中使用以下解决方案。
作为简单文字字符串的正则表达式的替代方法,您可以使用
str = "Test abc test test abc test...".split("abc").join("");
一般模式是
str.split(search).join(replacement)
在某些情况下,这曾经比使用 replaceAll
和正则表达式更快,但在现代浏览器中似乎不再如此。
基准测试:https://jsben.ch/TZYzj
结论:
如果您有性能关键用例(例如处理数百个字符串),请使用 Regexp 方法。但对于大多数典型的用例来说,不必担心特殊字符是非常值得的。
【讨论】:
我现在(2020 年)不鼓励使用 replaceAll。今年有更新的部分浏览器不支持caniuse.com/?search=replaceAll太早了 NodeJS 在 15.x 版本中支持replaceAll
。
在区分大小写的情况下怎么办
基准的普通替换功能不等同于正则表达式 /g。 “如果 pattern 是一个字符串,只有第一个匹配项会被替换。” EX: replaceAll_0("foo bar foo") => "bar foo" 当它应该只是 "bar" 时。 -MDN【参考方案4】:
使用带有g
标志集的正则表达式将全部替换:
someString = 'the cat looks like a cat';
anotherString = someString.replace(/cat/g, 'dog');
// anotherString now contains "the dog looks like a dog"
See here also
【讨论】:
【参考方案5】:这是一个基于公认答案的字符串原型函数:
String.prototype.replaceAll = function (find, replace)
var str = this;
return str.replace(new RegExp(find, 'g'), replace);
;
编辑
如果您的find
将包含特殊字符,那么您需要对它们进行转义:
String.prototype.replaceAll = function (find, replace)
var str = this;
return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]]/g, '\\$&'), 'g'), replace);
;
小提琴:http://jsfiddle.net/cdbzL/
【讨论】:
【参考方案6】:更新:
更新有点晚了,但是因为我只是偶然发现了这个问题,并注意到我之前的答案不是我满意的答案。由于问题涉及替换单个单词,令人难以置信的是没有人想到使用单词边界 (\b
)
'a cat is not a caterpillar'.replace(/\bcat\b/gi,'dog');
//"a dog is not a caterpillar"
这是一个简单的正则表达式,可以避免在大多数情况下替换部分单词。但是,破折号-
仍被视为单词边界。所以在这种情况下可以使用条件来避免替换像cool-cat
这样的字符串:
'a cat is not a cool-cat'.replace(/\bcat\b/gi,'dog');//wrong
//"a dog is not a cool-dog" -- nips
'a cat is not a cool-cat'.replace(/(?:\b([^-]))cat(?:\b([^-]))/gi,'$1dog$2');
//"a dog is not a cool-cat"
基本上,这个问题和这里的问题是一样的: Javascript replace " ' " with " '' "
@Mike,检查我在那里给出的答案... regexp 不是替换多次出现的 subsrting 的唯一方法,远非如此。思考灵活,思考分裂!
var newText = "the cat looks like a cat".split('cat').join('dog');
另外,为了防止替换单词部分 - 批准的答案也会这样做!你可以使用正则表达式来解决这个问题,我承认,这些正则表达式更复杂一些,结果也慢了一点:
var regText = "the cat looks like a cat".replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");
输出与接受的答案相同,但是,在此字符串上使用 /cat/g
表达式:
var oops = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/cat/g,'dog');
//returns "the dog looks like a dog, not a dogerpillar or cooldog" ??
糟糕,这可能不是您想要的。那是什么?恕我直言,一个仅有条件地替换“猫”的正则表达式。 (即不是单词的一部分),像这样:
var caterpillar = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");
//return "the dog looks like a dog, not a caterpillar or coolcat"
我的猜测是,这可以满足您的需求。当然,这不是完全证明,但它应该足以让你开始。我建议在这些页面上阅读更多内容。这将有助于完善此表达式以满足您的特定需求。
http://www.javascriptkit.com/jsref/regexp.shtml
http://www.regular-expressions.info
最后添加:
鉴于这个问题仍然有很多观点,我想我可以添加一个.replace
与回调函数一起使用的示例。在这种情况下,它极大地简化了表达式 并且 提供了更大的灵活性,例如替换为正确的大小写或一次性替换 cat
和 cats
:
'Two cats are not 1 Cat! They\'re just cool-cats, you caterpillar'
.replace(/(^|.\b)(cat)(s?\b.|$)/gi,function(all,char1,cat,char2)
//check 1st, capitalize if required
var replacement = (cat.charAt(0) === 'C' ? 'D' : 'd') + 'og';
if (char1 === ' ' && char2 === 's')
//replace plurals, too
cat = replacement + 's';
else
//do not replace if dashes are matched
cat = char1 === '-' || char2 === '-' ? cat : replacement;
return char1 + cat + char2;//return replacement string
);
//returns:
//Two dogs are not 1 Dog! They're just cool-cats, you caterpillar
【讨论】:
【参考方案7】:匹配全局正则表达式:
anotherString = someString.replace(/cat/g, 'dog');
【讨论】:
【参考方案8】:这些是最常见和可读的方法。
var str = "Test abc test test abc test test test abc test test abc"
方法一:
str = str.replace(/abc/g, "replaced text");
方法二:
str = str.split("abc").join("replaced text");
方法三:
str = str.replace(new RegExp("abc", "g"), "replaced text");
方法四:
while(str.includes("abc"))
str = str.replace("abc", "replaced text");
输出:
console.log(str);
// Test replaced text test test replaced text test test test replaced text test test replaced text
【讨论】:
【参考方案9】:用于替换单次使用:
var res = str.replace('abc', "");
对于多次替换使用:
var res = str.replace(/abc/g, "");
【讨论】:
【参考方案10】:str = str.replace(/abc/g, '');
或尝试replaceAll
方法,如this answer 中推荐的那样:
str = str.replaceAll('abc', '');
或:
var search = 'abc';
str = str.replaceAll(search, '');
编辑:关于replaceAll
可用性的说明
replaceAll
方法被添加到String
的原型中。这意味着它将可用于所有字符串对象/文字。
例子:
var output = "test this".replaceAll('this', 'that'); // output is 'test that'.
output = output.replaceAll('that', 'this'); // output is 'test this'
【讨论】:
【参考方案11】:在 JavaScript 中使用 RegExp
可以为您完成这项工作,只需执行类似以下代码的操作,不要忘记 /g
之后的 global:
var str ="Test abc test test abc test test test abc test test abc";
str = str.replace(/abc/g, '');
如果您考虑重用,请创建一个函数来为您执行此操作,但不建议这样做,因为它只是一个行函数,但如果您大量使用它,您可以编写如下内容:
String.prototype.replaceAll = String.prototype.replaceAll || function(string, replaced)
return this.replace(new RegExp(string, 'g'), replaced);
;
只需在您的代码中反复使用它,如下所示:
var str ="Test abc test test abc test test test abc test test abc";
str = str.replaceAll('abc', '');
但正如我之前提到的,它不会在要编写的行数或性能方面产生巨大差异,仅缓存函数可能会对长字符串产生更快的性能,并且如果您愿意,也是 DRY 代码的良好实践重复使用。
【讨论】:
【参考方案12】:假设你想用'x'替换所有'abc':
let some_str = 'abc def def lom abc abc def'.split('abc').join('x')
console.log(some_str) //x def def lom x x def
我试图想一些比修改字符串原型更简单的事情。
【讨论】:
【参考方案13】:使用正则表达式:
str.replace(/abc/g, '');
【讨论】:
【参考方案14】:替换单引号:
function JavaScriptEncode(text)
text = text.replace(/'/g,''')
// More encode here if required
return text;
【讨论】:
【参考方案15】:性能
今天 27.12.2019 我在 macOS v10.13.6 (High Sierra) 上针对所选解决方案进行测试。
结论
str.replace(/abc/g, '');
(C) 是一个很好的跨浏览器快速解决方案,适用于所有字符串。
基于split-join
(A,B) 或replace
(C,D) 的解决方案速度很快
基于 while
(E,F,G,H) 的解决方案速度很慢 - 通常小字符串慢约 4 倍,长字符串慢约 3000 倍 (!)李>
循环解决方案 (RA,RB) 速度较慢,不适用于长字符串
我还创建了自己的解决方案。看起来目前它是完成问题工作的最短的:
str.split`abc`.join``
str = "Test abc test test abc test test test abc test test abc";
str = str.split`abc`.join``
console.log(str);
详情
测试是在 Chrome 79.0、Safari 13.0.4 和 Firefox 71.0(64 位)上进行的。测试RA
和RB
使用递归。结果
短字符串 - 55 个字符
您可以在您的机器HERE 上运行测试。 Chrome 的结果:
长字符串:275 000 个字符
RA 和 RB 给出的递归解决方案
RangeError: 超出最大调用堆栈大小
对于 100 万个字符,它们甚至会破坏 Chrome
我尝试为其他解决方案执行 1M 个字符的测试,但 E,F,G,H 花费了太多时间,以至于浏览器要求我中断脚本,因此我将测试字符串缩减为 275K 个字符。您可以在您的机器HERE 上运行测试。 Chrome 的结果
测试中使用的代码
var t="Test abc test test abc test test test abc test test abc"; // .repeat(5000)
var log = (version,result) => console.log(`$version: $result`);
function A(str)
return str.split('abc').join('');
function B(str)
return str.split`abc`.join``; // my proposition
function C(str)
return str.replace(/abc/g, '');
function D(str)
return str.replace(new RegExp("abc", "g"), '');
function E(str)
while (str.indexOf('abc') !== -1) str = str.replace('abc', '');
return str;
function F(str)
while (str.indexOf('abc') !== -1) str = str.replace(/abc/, '');
return str;
function G(str)
while(str.includes("abc")) str = str.replace('abc', '');
return str;
// src: https://***.com/a/56989553/860099
function H(str)
let i = -1
let find = 'abc';
let newToken = '';
if (!str)
if ((str == null) && (find == null)) return newToken;
return str;
while ((
i = str.indexOf(
find, i >= 0 ? i + newToken.length : 0
)) !== -1
)
str = str.substring(0, i) +
newToken +
str.substring(i + find.length);
return str;
// src: https://***.com/a/22870785/860099
function RA(string, prevstring)
var omit = 'abc';
var place = '';
if (prevstring && string === prevstring)
return string;
prevstring = string.replace(omit, place);
return RA(prevstring, string)
// src: https://***.com/a/26107132/860099
function RB(str)
var find = 'abc';
var replace = '';
var i = str.indexOf(find);
if (i > -1)
str = str.replace(find, replace);
i = i + replace.length;
var st2 = str.substring(i);
if(st2.indexOf(find) > -1)
str = str.substring(0,i) + RB(st2, find, replace);
return str;
log('A ', A(t));
log('B ', B(t));
log('C ', C(t));
log('D ', D(t));
log('E ', E(t));
log('F ', F(t));
log('G ', G(t));
log('H ', H(t));
log('RA', RA(t)); // use reccurence
log('RB', RB(t)); // use reccurence
<p style="color:red">This snippet only presents codes used in tests. It not perform test itself!<p>
【讨论】:
现在这是一个非常深入的答案!非常感谢!不过,我很好奇的是为什么“new RegExp(...)”语法会带来这么大的改进。【参考方案16】:str = str.replace(new RegExp("abc", 'g'), "");
对我来说比上述答案更好。所以new RegExp("abc", 'g')
创建一个正则表达式匹配所有出现的文本('g'
标志)("abc"
)。第二部分被替换为空字符串(""
)。
str
是字符串,我们必须覆盖它,因为 replace(...)
只返回结果,而不是覆盖。在某些情况下,您可能想要使用它。
【讨论】:
警告!这种方法只适用于简单的情况,但永远不能成为主要选择。例如,如果您的字符串中存在任何RegExp Special Character.^$*+?()[|\\
,则无法返回预期结果。【参考方案17】:
这是不使用正则表达式的最快版本。
Revised jsperf
replaceAll = function(string, omit, place, prevstring)
if (prevstring && string === prevstring)
return string;
prevstring = string.replace(omit, place);
return replaceAll(prevstring, omit, place, string)
它几乎是 split 和 join 方法的 两倍。
正如评论中指出的那样,如果您的 omit
变量包含 place
,这将不起作用,例如:replaceAll("string", "s", "ss")
,因为它总是能够替换另一个出现的单词。
在我的递归替换中还有另一个带有变体的 jsperf,速度更快 (http://jsperf.com/replace-all-vs-split-join/12)!
2017 年 7 月 27 日更新:看起来 RegExp 现在在最近发布的 Chrome 59 中具有最快的性能。【讨论】:
【参考方案18】:循环直到出现次数为 0,如下所示:
function replaceAll(find, replace, str)
while (str.indexOf(find) > -1)
str = str.replace(find, replace);
return str;
【讨论】:
此方法危险,请勿使用。如果替换字符串包含搜索关键字,则会发生无限循环。至少,将.indexOf
的结果存储在一个变量中,并将这个变量作为.indexOf
的第二个参数(减去关键字的长度,加上替换字符串的长度)。【参考方案19】:
如果您要查找的内容已经在字符串中,并且您没有方便的正则表达式转义器,则可以使用 join/split:
function replaceMulti(haystack, needle, replacement)
return haystack.split(needle).join(replacement);
someString = 'the cat looks like a cat';
console.log(replaceMulti(someString, 'cat', 'dog'));
【讨论】:
【参考方案20】:function replaceAll(str, find, replace)
var i = str.indexOf(find);
if (i > -1)
str = str.replace(find, replace);
i = i + replace.length;
var st2 = str.substring(i);
if(st2.indexOf(find) > -1)
str = str.substring(0,i) + replaceAll(st2, find, replace);
return str;
【讨论】:
【参考方案21】:我喜欢这种方法(看起来更干净一些):
text = text.replace(new RegExp("cat","g"), "dog");
【讨论】:
【参考方案22】:var str = "ff ff f f a de def";
str = str.replace(/f/g,'');
alert(str);
http://jsfiddle.net/ANHR9/
【讨论】:
【参考方案23】:while (str.indexOf('abc') !== -1)
str = str.replace('abc', '');
【讨论】:
【参考方案24】:不使用任何正则表达式的最简单方法是像这里的代码一样拆分和加入:
var str = "Test abc test test abc test test test abc test test abc";
console.log(str.split('abc').join(''));
【讨论】:
【参考方案25】:如果字符串包含类似abccc
的模式,你可以使用这个:
str.replace(/abc(\s|$)/g, "")
【讨论】:
【参考方案26】:前面的答案太复杂了。只需像这样使用替换功能:
str.replace(/your_regex_pattern/g, replacement_string);
例子:
var str = "Test abc test test abc test test test abc test test abc";
var res = str.replace(/[abc]+/g, "");
console.log(res);
【讨论】:
【参考方案27】:截至 2020 年 8 月,ECMAScript 中有一个 Stage 4 proposal,它将 replaceAll
方法添加到 String
。
现在 Chrome 85+、Edge 85+、Firefox 77+、Safari 13.1+ 支持它。
用法同replace
方法:
String.prototype.replaceAll(searchValue, replaceValue)
这是一个示例用法:
'Test abc test test abc test.'.replaceAll('abc', 'foo'); // -> 'Test foo test test foo test.'
most modern browsers 支持,但存在 polyfill:
core-js es-shims在实验标志 --harmony-string-replaceall
后面的 V8 引擎中支持它。
在V8 website 上阅读更多信息。
【讨论】:
According to MDN,这从 Firefox 77 和 Chromium 85 开始可用。【参考方案28】:如果您试图确保您要查找的字符串即使在替换后也不存在,则需要使用循环。
例如:
var str = 'test aabcbc';
str = str.replace(/abc/g, '');
完成后,您仍将拥有“测试 abc”!
解决这个问题的最简单循环是:
var str = 'test aabcbc';
while (str != str.replace(/abc/g, ''))
str.replace(/abc/g, '');
但这会在每个循环中运行两次替换。也许(有被否决的风险)可以组合成一种更高效但可读性更低的形式:
var str = 'test aabcbc';
while (str != (str = str.replace(/abc/g, '')))
// alert(str); alerts 'test '!
这在查找重复字符串时特别有用。 例如,如果我们有 'a,,,b' 并且我们希望删除所有重复的逗号。 [在这种情况下,可以使用 .replace(/,+/g,','),但在某些时候正则表达式变得复杂且速度慢到足以代替循环。]
【讨论】:
【参考方案29】:虽然人们已经提到了正则表达式的使用,但是如果你想替换文本而不考虑文本的大小写,那么有一个更好的方法。喜欢大写或小写。使用以下语法
//Consider below example
originalString.replace(/stringToBeReplaced/gi, '');
//Output will be all the occurrences removed irrespective of casing.
您可以参考详细示例here。
【讨论】:
来自示例站点:“/toBeReplacedString/gi 是您需要使用的正则表达式。这里 g 表示全局匹配,i 表示不区分大小写。默认情况下,正则表达式区分大小写”【参考方案30】:String.prototype.replaceAll
- ECMAScript 2021
新的String.prototype.replaceAll()
方法返回一个新字符串,其中模式的所有匹配项都被替换。模式可以是字符串或正则表达式,替换可以是字符串或每次匹配调用的函数。
const message = 'dog barks meow meow';
const messageFormatted = message.replaceAll('meow', 'woof')
console.log(messageFormatted);
【讨论】:
replaceAll
已在近 20 个其他答案和 cmets 中被建议,包括接受的答案和票数最高的答案。这增加了什么?以上是关于如何替换 JavaScript 中所有出现的字符串的主要内容,如果未能解决你的问题,请参考以下文章