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

javascript string replace

我的 JavaScript 代码中有这个字符串:

"Test abc test test abc test test test abc test test abc"

正在做:

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

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

我怎样才能替换它的所有出现?

ababa 中出现的所有 aba 替换为 ca 时,您期望得到什么结果? cabaabcacca

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< /i> 是一个字符串,替换所有出现的 searchValue(就好像使用了 .split(searchValue).join(replaceValue) 或全局 & 正确转义的正则表达式)。如果 searchValue 是非全局正则表达式,则抛出异常”

使用正则表达式而不是字符串,应该看起来像 str.replace(/abc/g, ''); 所以 g 获取所有匹配项。

i
izogfif

截至 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 NetworkJavaScript 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, "\\$&")

您还需要转义替换字符串(考虑 escapeRegExp 如何在替换字符串中使用 $& 来实现特殊行为)。将最后一个代码块中的最后一个 replace 更改为 replace.replace(/\$/g, '$$$$')。请参阅 stackoverflow.com/a/6969486/2730641 测试用例:replaceAll('abc def abc', 'abc', '$&@%#!') // Censor 'abc'

P
Peter Mortensen

为了完整起见,我开始考虑应该使用哪种方法来做到这一点。正如本页其他答案所建议的,基本上有两种方法可以做到这一点。

注意: 一般来说,不推荐在 JavaScript 中扩展内置原型。我只是为了说明的目的而提供字符串原型的扩展,在 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原型的方法的错误,有什么解决方案吗?

M
Mario Petrovic

更新:在最流行的浏览器的最新版本中,您可以使用 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

M
Mario Petrovic

使用设置了 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

M
Mario Petrovic

这是一个基于接受的答案的字符串原型函数:

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/

M
Mario Petrovic

更新:

更新有点晚了,但是因为我刚刚偶然发现了这个问题,并注意到我之前的答案不是我满意的答案。由于问题涉及替换单个单词,令人难以置信的是没有人想到使用单词边界(\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,检查我在那里给出的答案......正则表达式不是替换多次出现的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 示例。在这种情况下,它极大地简化了表达式 并且 提供了更大的灵活性,例如用正确的大写替换或一次性替换 catcats

'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
M
Mario Petrovic

这些是最常见和可读的方法。

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
s
scronide

匹配全局正则表达式:

anotherString = someString.replace(/cat/g, 'dog');
M
Mihai Chelaru

更换单次使用:

var res = str.replace('abc', "");

更换多次使用:

var res = str.replace(/abc/g, "");
n
nik7
str = str.replace(/abc/g, '');

或尝试 this answer 中推荐的 replaceAll 方法:

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'
A
Alireza

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 代码的良好实践。

P
Peter Mortensen

假设你想用 '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

我试图考虑比修改字符串原型更简单的事情。

P
Peter Mortensen

使用正则表达式:

str.replace(/abc/g, '');
C
Community

表现

今天 27.12.2019 我在 macOS v10.13.6 (High Sierra) 上针对所选解决方案执行测试。

结论

str.replace(/abc/g, ''); (C) 是一个很好的跨浏览器快速解决所有字符串的方法。

基于拆分连接 (A,B) 或替换 (C,D) 的解决方案速度很快

基于 while (E,F,G,H) 的解决方案很慢 - 通常小字符串慢约 4 倍,长字符串慢约 3000 倍 (!)

递归解决方案(RA,RB)很慢,不适用于长字符串

我还创建了自己的解决方案。看起来目前它是完成问题工作的最短的一个:

str.split`abc`.join``

str = "测试 abc 测试测试 abc 测试测试 abc 测试测试 abc"; str = str.split`abc`.join`` console.log(str);

细节

测试在 Chrome 79.0、Safari 13.0.4 和 Firefox 71.0(64 位)上进行。测试 RARB 使用递归。结果

https://i.stack.imgur.com/si5UK.png

短字符串 - 55 个字符

您可以在您的机器 HERE 上运行测试。铬的结果:

https://i.stack.imgur.com/Ctf18.png

长字符串:275 000 个字符

递归解 RA 和 RB 给出

RangeError:超出最大调用堆栈大小

对于 100 万个字符,他们甚至会破坏 Chrome

https://i.stack.imgur.com/dNkYp.png

我尝试为其他解决方案执行 1M 个字符的测试,但是 E,F,G,H 花费了太多时间,以至于浏览器要求我中断脚本,所以我将测试字符串缩小到 275K 个字符。您可以在您的机器 HERE 上运行测试。铬的结果

https://i.stack.imgur.com/0uEgk.png

测试中使用的代码

var t="测试 abc 测试测试 abc 测试测试 abc 测试测试 abc"; // .repeat(5000) var log = (version,result) => console.log(`${version}: ${result}`);函数 A(str) { return str.split('abc').join(''); } function B(str) { return str.split`abc`.join`; // 我的提议 } 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', ''); } 返回字符串; } function F(str) { while (str.indexOf('abc') !== -1) { str = str.replace(/abc/, ''); } 返回字符串; } 函数 G(str) { while(str.includes("abc")) { str = str.replace('abc', ''); } 返回字符串; } // src: https://stackoverflow.com/a/56989553/860099 function H(str) { let i = -1 let find = 'abc';让 newToken = ''; if (!str) { if ((str == null) && (find == null)) return newToken;返回字符串; } while (( i = str.indexOf( find, i >= 0 ? i + newToken.length : 0 )) !== -1 ) { str = str.substring(0, i) + newToken + str.substring( i + find.length); } 返回字符串; } // src: https://stackoverflow.com/a/22870785/860099 function RA(string, prevstring) { var omit = 'abc';变量位置 = ''; if (prevstring && string === prevstring) 返回字符串; prevstring = string.replace(省略,放置); return RA(prevstring, string) } // src: https://stackoverflow.com/a/26107132/860099 function RB(str) { var find = 'abc'; var 替换 = ''; var i = str.indexOf(find); if (i > -1){ str = str.replace(查找, 替换); i = i + 替换长度; var st2 = str.substring(i); if(st2.indexOf(find) > -1){ str = str.substring(0,i) + RB(st2, 查找, 替换); } } 返回字符串; } log('A', A(t));日志('B',B(t));日志('C', C(t));日志('D', D(t));日志('E',E(t));日志('F', F(t));日志('G', G(t)); log('H', H(t));日志('RA',RA(t)); // 使用递归 log('RB', RB(t)); // 使用重复

这个片段只展示了测试中使用的代码。它本身不执行测试!

现在这是一个非常深入的答案!非常感谢!虽然,我很好奇的是为什么“new RegExp(...)”语法会带来这么大的改进。

T
Termininja

替换单引号:

function JavaScriptEncode(text){
    text = text.replace(/'/g,'&apos;')
    // More encode here if required

    return text;
}
c
csomakk
str = str.replace(new RegExp("abc", 'g'), "");

对我来说比上面的答案更好。因此 new RegExp("abc", 'g') 创建了一个匹配文本 ("abc") 的所有出现 ('g' 标志) 的正则表达式。第二部分是被替换的内容,在您的情况下为空字符串 ("")。 str 是字符串,我们必须覆盖它,因为 replace(...) 只返回结果,而不是覆盖。在某些情况下,您可能想要使用它。

警告!这种方法只适用于简单的情况,但永远不能成为主要选择。例如,如果您的字符串中存在任何 RegExp Special Character .^$*+?()[{|\\,则无法返回预期结果。

C
Cole Lawrence

这是不使用正则表达式的最快版本。

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)
}

它几乎是拆分和连接方法的两倍。

正如此处的评论所指出的,如果您的 omit 变量包含 place,这将不起作用,例如:replaceAll("string", "s", "ss"),因为它总是能够替换另一个出现的单词。

在我的递归替换中还有另一个带有变体的 jsperf,它运行得更快(http://jsperf.com/replace-all-vs-split-join/12)!

2017 年 7 月 27 日更新:看起来 RegExp 现在在最近发布的 Chrome 59 中具有最快的性能。

n
nik7

循环它直到出现次数为 0,如下所示:

function replaceAll(find, replace, str) {
    while (str.indexOf(find) > -1) {
        str = str.replace(find, replace);
    }
    return str;
}

这种方法很危险,不要使用。如果替换字符串包含搜索关键字,则会发生无限循环。至少,将 .indexOf 的结果存储在一个变量中,并将此变量用作 .indexOf 的第二个参数(减去关键字的长度,加上替换字符串的长度)。

p
pitust

如果您要查找的内容已经在字符串中,并且您没有方便的正则表达式转义器,则可以使用连接/拆分:

function replaceMulti(haystack, needle, replacement) { return haystack.split(needle).join(replacement); } someString = '这只猫看起来像一只猫'; console.log(replaceMulti(someString, 'cat', 'dog'));

T
Tim Rivoli
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;
}
P
Peter Mortensen

我喜欢这种方法(它看起来更干净一些):

text = text.replace(new RegExp("cat","g"), "dog"); 
p
pkdkk
var str = "ff ff f f a de def";
str = str.replace(/f/g,'');
alert(str);

http://jsfiddle.net/ANHR9/

z
zdennis
while (str.indexOf('abc') !== -1)
{
    str = str.replace('abc', '');
}
R
Ran Marciano

不使用任何正则表达式的最简单方法是像这里的代码一样拆分和加入:

var str = "测试 abc 测试测试 abc 测试测试 abc 测试测试 abc"; console.log(str.split('abc').join(''));

R
Ran Turner

String.prototype.replaceAll - ECMAScript 2021

新的 String.prototype.replaceAll() 方法返回一个新字符串,其中模式的所有匹配项都被替换。模式可以是字符串或正则表达式,替换可以是字符串或每次匹配调用的函数。

const message = '狗叫喵喵';常量 messageFormatted = message.replaceAll('meow', 'woof') console.log(messageFormatted);

replaceAll 已在近 20 个其他答案和评论中被推荐,包括接受的答案和票数最高的答案。这增加了什么?

如果您正在寻找 Node.js 中的方法,这将不起作用。 replit.com/@RixTheTyrunt/rixxyplayer-parser?v=1

@RixTheTyrunt 当然,这将适用于最新版本的 Node.js。

3
3 revs, 2 users 78%

如果字符串包含类似 abccc 的模式,您可以使用:

str.replace(/abc(\s|$)/g, "")
T
Thomas Orlita

截至 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:

核心js

es-shims

它在实验性标志 --harmony-string-replaceall 后面的 V8 引擎中受支持。在 V8 website 上阅读更多信息。

According to MDN,这从 Firefox 77 和 Chromium 85 开始可用。

P
Peter Mortensen

前面的答案太复杂了。只需像这样使用替换功能:

str.replace(/your_regex_pattern/g, replacement_string);

例子:

var str = "测试 abc 测试测试 abc 测试测试 abc 测试测试 abc"; var res = str.replace(/[abc]+/g, "");控制台.log(res);

S
SamGoody

如果您要确保即使在替换后也不存在您要查找的字符串,则需要使用循环。

例如:

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,','),但在某些时候,正则表达式会变得复杂且慢到足以代替循环。]

e
evandrix

尽管人们已经提到了正则表达式的使用,但是如果你想替换文本而不考虑文本的大小写,那么有一个更好的方法。喜欢大写或小写。使用以下语法

//Consider below example
originalString.replace(/stringToBeReplaced/gi, '');

//Output will be all the occurrences removed irrespective of casing.

您可以参考详细示例here

来自示例站点:“/toBeReplacedString/gi 是您需要使用的正则表达式。这里 g 代表全局匹配,i 代表不区分大小写。默认情况下,正则表达式区分大小写”