开发者问题收集

如何替换 JavaScript 中所有出现的字符串?

2009-07-17
4554103

给定一个字符串:

string = "Test abc test test abc test test test abc test test abc";

这似乎只能删除上面字符串中第一次出现的 abc

string = string.replace('abc', '');

如何替换 所有 出现的字符串?

3个回答

截至 2020 年 8 月: 现代浏览器支持 ECMAScript 2021 语言规范定义的 String.replaceAll() 方法


对于较旧/旧版浏览器:

function escapeRegExp(str) {
  return str.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 开发者网络 JavaScript 正则表达式指南 中介绍了此内容,其中介绍了以下实用函数(自最初编写此答案以来,该函数至少已更改两次,因此请务必检查 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);
}
Sean Bright
2009-07-17

为了完整起见,我开始思考应该使用哪种方法来执行此操作。根据本页上其他答案的建议,基本上有两种方法可以做到这一点。

注意: 通常,通常不建议扩展 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);
};

由于不太了解正则表达式在幕后如何工作,因此过去我倾向于使用拆分和连接实现,而不考虑性能。当我确实想知道哪个效率更高以及效率高出多少时,我以此为借口去找出答案。

在我的 Chrome Windows 8 机器上, 基于正则表达式的实现是最快的 ,而 拆分和连接实现慢了 53% 。这意味着对于我使用的 lorem ipsum 输入,正则表达式的速度是原来的两倍。

查看此 基准测试 ,将这两个实现相互运行。


正如@ThomasLeduc 和其他人在下面的评论中指出的那样,如果 search 包含某些保留为 正则表达式中的特殊字符 的字符,则基于正则表达式的实现可能会出现问题。该实现假定调用者将事先对字符串进行转义,或者仅传递不包含 正则表达式 (MDN) 中表中字符的字符串。

MDN 还提供了一种转义字符串的实现。如果这也被标准化为 RegExp.escape(str) ,那就太好了,但可惜的是,它不存在:

function escapeRegExp(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}

我们可以在 String.prototype.replaceAll 实现中调用 escapeRegExp ,但是,我不确定这会对性能产生多大影响(甚至可能对不需要转义的字符串产生影响,例如所有字母数字字符串)。

Cory Gross
2013-07-12

在大多数流行浏览器的最新版本中,您可以使用 replaceAll 如下所示:

let result = "1 abc 2 abc 3".replaceAll("abc", "xyz");
// `result` is "1 xyz 2 xyz 3"

但请先检查 我可以使用吗 或其他兼容性表,以确保您所针对的浏览器已首先添加对它的支持。


对于 Node.js 和与旧版/非当前浏览器的兼容性:

注意:请勿在性能关键代码中使用以下解决方案。

作为简单文字字符串的正则表达式的替代,您可以使用

str = "Test abc test test abc test...".split("abc").join("");

一般模式是

str.split(search).join(replacement)

在某些情况下,这比使用 replaceAll 和正则表达式更快,但在现代浏览器中似乎不再如此。

基准测试: https://jsben.ch/TZYzj

结论:

如果您有一个性能至关重要的用例(例如,处理数百个字符串),请使用正则表达式方法。但对于大多数典型用例,这非常值得,因为不必担心特殊字符。

Matthew Crumley
2009-07-17