如何替换 JavaScript 中所有出现的字符串?
- 2024-11-02 21:00:00
- admin 原创
- 176
问题描述:
给定一个字符串:
string = "Test abc test test abc test test test abc test test abc";
这似乎只能删除abc
上面字符串中第一次出现的:
string = string.replace('abc', '');
我如何替换所有出现的它?
解决方案 1:
截至 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);
}
解决方案 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 输入,正则表达式的速度是后者的两倍。
检查一下对这两个实现进行相互运行的基准测试。
正如@ThomasLeduc 和其他人在下面的评论中指出的那样,如果基于正则表达式的实现包含某些在正则表达式中search
保留为特殊字符的字符,则可能存在问题。 该实现假定调用者将事先转义字符串,或者仅传递不包含正则表达式(MDN)表中的字符的字符串。
MDN 还提供了一个实现来转义我们的字符串。如果这也被标准化为 那就太好了RegExp.escape(str)
,但遗憾的是,它不存在:
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[]\\]/g, "\\$&"); // $& means the whole matched string
}
escapeRegExp
我们可以在我们的实现中调用String.prototype.replaceAll
,但是,我不确定这会对性能产生多大影响(甚至对于不需要转义的字符串,如所有字母数字字符串)。
解决方案 3:
在大多数流行浏览器的最新版本中,您可以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
,但在现代浏览器中似乎不再如此。
结论:
如果您有性能至关重要的用例(例如,处理数百个字符串),请使用正则表达式方法。但对于大多数典型用例,这非常值得,因为不必担心特殊字符。
解决方案 4:
这些是最常见且最易读的方法。
var str = "Test abc test test abc test test test abc test test abc"
方法 1:
str = str.replace(/abc/g, "replaced text");
方法 2:
str = str.split("abc").join("replaced text");
方法 3:
str = str.replace(new RegExp("abc", "g"), "replaced text");
方法 4:
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
解决方案 5:
使用单词边界()
'a cat is not a caterpillar'.replace(/cat/gi,'dog');
//"a dog is not a caterpillar"
这是一个简单的正则表达式,在大多数情况下可以避免替换单词的部分内容。但是,破折号-
仍被视为单词边界。因此,在这种情况下可以使用条件语句来避免替换字符串,例如cool-cat
:
'a cat is not a cool-cat'.replace(/cat/gi,'dog');//wrong
//"a dog is not a cool-dog" -- nips
'a cat is not a cool-cat'.replace(/(?:([^-]))cat(?:([^-]))/gi,'$1dog$2');
//"a dog is not a cool-cat"
基本上,这个问题与这里的问题相同:
在 JavaScript 中将“ ' ”替换为“ '' ”
正则表达式并不是替换多次出现的子字符串的唯一方法,远非如此。灵活思考,拆分思考!
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" ??
哎呀,这可能不是你想要的。那么,什么是呢?恕我直言,一个正则表达式只会有条件地替换“cat”(即,不是单词的一部分),如下所示:
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"
我猜这可以满足您的需求。当然,它不是万无一失的,但应该足以让您入门。我建议您在这些页面上阅读更多内容。这将有助于完善此表达式以满足您的特定需求。
RegExp(正则表达式)对象
正则表达式.info
以下是与回调函数一起使用的示例.replace
。在这种情况下,它大大简化了表达式并提供了更大的灵活性,例如用正确的大写字母替换或一次性替换cat
两者:cats
'Two cats are not 1 Cat! They\'re just cool-cats, you caterpillar'
.replace(/(^|.)(cat)(s?.|$)/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
解决方案 6:
与全局正则表达式匹配:
anotherString = someString.replace(/cat/g, 'dog');
解决方案 7:
str = str.replace(/abc/g, '');
或者尝试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'
解决方案 8:
使用正则表达式:
str.replace(/abc/g, '');
解决方案 9:
表现
今天,2019 年 12 月 27 日,我在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);
Run code snippetHide resultsExpand snippet
细节
测试在 Chrome 79.0、Safari 13.0.4 和 Firefox 71.0(64 位)上进行。测试RA
使用RB
递归。结果
短字符串 - 55 个字符
您可以在此处在您的机器上运行测试。Chrome 的结果:
长字符串:275 000 个字符
递归解RA和RB给出
RangeError:超出最大调用堆栈大小
为了 100 万个字符,他们甚至会破坏 Chrome
我尝试对其他解决方案执行 1M 字符的测试,但E、F、G、H花费的时间太长,浏览器要求我中断脚本,因此我将测试字符串缩小到 275K 字符。您可以在此处在您的机器上运行测试。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://stackoverflow.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://stackoverflow.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://stackoverflow.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>
Run code snippetHide resultsExpand snippet
解决方案 10:
循环直到出现次数达到 0,如下所示:
function replaceAll(find, replace, str) {
while (str.indexOf(find) > -1) {
str = str.replace(find, replace);
}
return str;
}
解决方案 11:
这是不使用正则表达式的最快的版本。
修订版 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 中具有最快的性能。
解决方案 12:
如果要查找的内容已在字符串中,并且手边没有正则表达式转义符,则可以使用 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'));
运行代码片段Hide results展开片段
解决方案 13:
当然,在2021 年,正确答案是:
String.prototype.replaceAll()
console.log(
'Change this and this for me'.replaceAll('this','that') // Normal case
);
console.log(
'aaaaaa'.replaceAll('aa','a') // Challenged case
);
运行代码片段Hide results展开片段
如果您不想处理replace() + RegExp。
但是如果浏览器是 2020 年之前的呢?
在这种情况下,我们需要polyfill(强制旧浏览器支持新功能)(我认为几年内都是必要的)。我在答案中找不到完全正确的方法。所以我建议将这个函数定义为 polyfill。
我建议的 polyfill 选项replaceAll
:
replaceAll
polyfill (带有全局标志错误) (更原则性的版本)
if (!String.prototype.replaceAll) { // Check if the native function not exist
Object.defineProperty(String.prototype, 'replaceAll', { // Define replaceAll as a prototype for (Mother/Any) String
configurable: true, writable: true, enumerable: false, // Editable & non-enumerable property (As it should be)
value: function(search, replace) { // Set the function by closest input names (For good info in consoles)
return this.replace( // Using native String.prototype.replace()
Object.prototype.toString.call(search) === '[object RegExp]' // IsRegExp?
? search.global // Is the RegEx global?
? search // So pass it
: function(){throw new TypeError('replaceAll called with a non-global RegExp argument')}() // If not throw an error
: RegExp(String(search).replace(/[.^$*+?()[{|\\]/g, "\\$&"), "g"), // Replace all reserved characters with '\' then make a global 'g' RegExp
replace); // passing second argument
}
});
}
replaceAll
polyfill(本身缺少处理全局标志)(我的第一偏好) -为什么?
if (!String.prototype.replaceAll) { // Check if the native function not exist
Object.defineProperty(String.prototype, 'replaceAll', { // Define replaceAll as a prototype for (Mother/Any) String
configurable: true, writable: true, enumerable: false, // Editable & non-enumerable property (As it should be)
value: function(search, replace) { // Set the function by closest input names (For good info in consoles)
return this.replace( // Using native String.prototype.replace()
Object.prototype.toString.call(search) === '[object RegExp]' // IsRegExp?
? search.global // Is the RegEx global?
? search // So pass it
: RegExp(search.source, //([a-z]*)$/.exec(search.toString())[1] + 'g') // If not, make a global clone from the RegEx
: RegExp(String(search).replace(/[.^$*+?()[{|\\]/g, "\\$&"), "g"), // Replace all reserved characters with '\' then make a global 'g' RegExp
replace); // passing second argument
}
});
}
最小化(我的第一选择):
if(!String.prototype.replaceAll){Object.defineProperty(String.prototype,'replaceAll',{configurable:!0,writable:!0,enumerable:!1,value:function(search,replace){return this.replace(Object.prototype.toString.call(search)==='[object RegExp]'?search.global?search:RegExp(search.source,//([a-z]*)$/.exec(search.toString())[1]+'g'):RegExp(String(search).replace(/[.^$*+?()[{|\\]/g,"\\$&"),"g"),replace)}})}
尝试一下:
显示代码片段
if(!String.prototype.replaceAll){Object.defineProperty(String.prototype,'replaceAll',{configurable:!0,writable:!0,enumerable:!1,value:function(search,replace){return this.replace(Object.prototype.toString.call(search)==='[object RegExp]'?search.global?search:RegExp(search.source,//([a-z]*)$/.exec(search.toString())[1]+'g'):RegExp(String(search).replace(/[.^$*+?()[{|\\]/g,"\\$&"),"g"),replace)}})}
console.log(
'Change this and this for me'.replaceAll('this','that')
); // Change that and that for me
console.log(
'aaaaaa'.replaceAll('aa','a')
); // aaa
console.log(
'{} (*) (*) (RegEx) (*) (*) (\\*) [reserved characters]'.replaceAll('(*)','X')
); // {} X X (RegEx) X X (*) [reserved characters]
console.log(
'How (replace) (XX) with $1?'.replaceAll(/(xx)/gi,'$$1')
); // How (replace) ($1) with $1?
console.log(
'Here is some numbers 1234567890 1000000 123123.'.replaceAll(/d+/g,'***')
); // Here is some numbers *** *** *** and need to be replaced.
console.log(
'Remove numbers under 233: 236 229 711 200 5'.replaceAll(/d+/g, function(m) {
return parseFloat(m) < 233 ? '' : m
})
); // Remove numbers under 233: 236 711
console.log(
'null'.replaceAll(null,'x')
); // x
// The difference between My first preference and the original:
// Now in 2022 with browsers > 2020 it should throw an error (But possible it be changed in future)
// console.log(
// 'xyz ABC abc ABC abc xyz'.replaceAll(/abc/i,'')
// );
// Browsers < 2020:
// xyz xyz
// Browsers > 2020
// TypeError: String.prototype.replaceAll called with a non-global RegExp
Run code snippetHide resultsExpand snippet
浏览器支持:
Internet Explorer 9及更高版本(基于Internet Explorer 11)。
所有其他浏览器(2012 年之后)。
如果第一个参数输入为:
,,,,,,... ,,,,,... ,则结果与本机replaceAll相同。null
`undefinedObject
FunctionDate
RegExpNumber
String`
参考:22.1.3.19 String.prototype.replaceAll (searchValue, replaceValue)
+ RegExp 语法
重要提示:正如一些专业人士提到的那样,答案中建议的许多递归函数都会返回错误的结果。(使用上面代码片段中的挑战.split('searchValue').join('replaceValue')
案例尝试它们。)也许一些棘手的方法或一些管理良好的函数会给出相同的结果,但性能肯定比native replaceAll()
/ polyfill replaceAll()
/低得多replace() + RegExp
polyfill 分配的其他方法
虽然简单,但支持更老的浏览器(最好避免)
例如,我们也可以支持 IE7+,通过不使用Object.defineProperty()并使用我以前的简单赋值方法:
if (!String.prototype.replaceAll) {
String.prototype.replaceAll = function(search, replace) { // <-- Naive method for assignment
// ... (Polyfill code Here)
}
}
并且它应该可以很好地用于 IE7+ 上的基本用途。
但正如@sebastian-simon在此处解释的那样,如果用于更高级的用途,这可能会引发次要问题。例如:
for (var k in 'hi') console.log(k);
// 0
// 1
// replaceAll <-- ?
完全值得信赖,但很重
事实上,我建议的选项有点乐观。就像我们信任环境(浏览器和Node.js)一样,它肯定适用于 2012-2021 年左右。而且它是一个标准/著名的环境,因此不需要任何特殊考虑。
但是可能会有更老的浏览器或一些意想不到的问题,而 polyfill 仍然可以支持和解决更多可能的环境问题。因此,如果我们需要尽可能大的支持,我们可以使用以下polyfill 库:
特别针对replaceAll:
<script src="https://polyfill.io/v3/polyfill.min.js?features=String.prototype.replaceAll"></script>
解决方案 14:
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;
}
解决方案 15:
我喜欢这种方法(看起来更干净一些):
text = text.replace(new RegExp("cat","g"), "dog");
解决方案 16:
while (str.indexOf('abc') !== -1)
{
str = str.replace('abc', '');
}
解决方案 17:
截至 2020 年 8 月,ECMAScript 的第 4 阶段提案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.'
它被大多数现代浏览器支持,但是存在 polyfill:
core-js
es垫片
它由V8引擎通过一个实验性标志支持--harmony-string-replaceall
。更多信息请阅读V8 网站。
解决方案 18:
如果字符串包含类似的模式abccc
,则可以使用以下命令:
str.replace(/abc(s|$)/g, "")
解决方案 19:
前面的答案太复杂了。只需使用这样的替换函数:
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);
运行代码片段Hide results展开片段
解决方案 20:
经过多次尝试和失败后,我发现下面的函数似乎是浏览器兼容性和易用性方面最好的全能型函数。这是我找到的唯一适用于旧浏览器的解决方案。(是的,尽管旧浏览器不受欢迎且过时,但一些旧版应用程序仍然大量使用OLE浏览器(例如旧的Visual Basic 6应用程序或带有表单的Excel .xlsm 宏)。)
无论如何,这是一个简单的功能。
function replaceAll(str, match, replacement){
return str.split(match).join(replacement);
}
解决方案 21:
尽管人们提到了使用正则表达式,但如果您想替换文本而不考虑文本的大小写,还有更好的方法。例如大写或小写。使用以下语法:
// Consider the below example
originalString.replace(/stringToBeReplaced/gi, '');
// The output will be all the occurrences removed irrespective of casing.
您可以参考此处的详细示例。
解决方案 22:
如果您试图确保所查找的字符串即使在替换后也不会存在,则需要使用循环。
例如:
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,','),但在某些时候,正则表达式变得复杂且速度慢到需要循环。]
解决方案 23:
我的实现,非常容易理解
function replaceAll(string, token, newtoken) {
if(token!=newtoken)
while(string.indexOf(token) > -1) {
string = string.replace(token, newtoken);
}
return string;
}
解决方案 24:
您可以简单地使用以下方法
/**
* Replace all the occerencess of $find by $replace in $originalString
* @param {originalString} input - Raw string.
* @param {find} input - Target key word or regex that need to be replaced.
* @param {replace} input - Replacement key word
* @return {String} Output string
*/
function replaceAll(originalString, find, replace) {
return originalString.replace(new RegExp(find, 'g'), replace);
};
解决方案 25:
以下功能对我有用:
String.prototype.replaceAllOccurence = function(str1, str2, ignore)
{
return this.replace(new RegExp(str1.replace(/([/,!\\^${}[]().*+?|<>-&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/$/g,"$$$$"):str2);
} ;
现在像这样调用函数:
"you could be a Project Manager someday, if you work like this.".replaceAllOccurence ("you", "I");
只需将此代码复制并粘贴到浏览器控制台中即可进行测试。
解决方案 26:
我使用拆分和连接或此功能:
function replaceAll(text, busca, reemplaza) {
while (text.toString().indexOf(busca) != -1)
text = text.toString().replace(busca, reemplaza);
return text;
}
解决方案 27:
现在已经有了一份完整的提案,用于集成String.prototype.replaceAll
到官方规范中。最终,开发人员将不必自己提出实现方案replaceAll
- 相反,现代 JavaScript 引擎将原生支持它。
该提案目前处于第 4 阶段,这意味着一切都已完成,剩下的就是浏览器开始实现它。
它已在 Chrome、Firefox 和 Safari 的最新版本中发布。
以下是实施细节:
根据当前的 TC39 共识,除以下两种情况外,在所有情况下的
String.prototype.replaceAll
行为均相同:String.prototype.replace
如果
searchValue
是字符串,String.prototype.replace
则仅替换单次出现的searchValue
,而如果是字符串,String.prototype.replaceAll
则替换所有出现的searchValue
(如同.split(searchValue).join(replaceValue)
或使用了全局且正确转义的正则表达式)。如果
searchValue
是非全局正则表达式,String.prototype.replace
则替换单个匹配项,否则String.prototype.replaceAll
抛出异常。这样做是为了避免缺少全局标志(暗示“不替换全部”)和被调用方法的名称(强烈建议“替换全部”)之间固有的混淆。值得注意的是,
String.prototype.replaceAll
其行为就像是一个全局正则表达式String.prototype.replace
一样。searchValue
您可以在此处看到符合规范的polyfill 。
在受支持的环境中,以下代码片段将记录foo-bar-baz
,而不会引发错误:
const str = 'foo bar baz';
console.log(
str.replaceAll(' ', '-')
);
运行代码片段Hide results展开片段
解决方案 28:
如果您选择使用库,那么您将获得库函数附带的测试和社区支持的好处。例如,string.js库有一个 replaceAll() 函数,可以执行您所需的操作:
// Include a reference to the string.js library and call it (for example) S.
str = S(str).replaceAll('abc', '').s;
解决方案 29:
在我的应用程序中,我使用了一个功能最强大的自定义函数,即使split/join
在更简单的案例中包装解决方案,它在 Chrome 60 和 Firefox 54 ( JSBEN.CH ) 中的运行速度也比其他解决方案快一点。我的电脑运行的是 Windows 7 64 位。
优点是,这个自定义函数可以同时使用字符串或字符处理许多替换,这对于某些应用程序来说可以是一种捷径。
与上述拆分/连接解决方案一样,与正则表达式方法不同,下面的解决方案不存在转义字符的任何问题。
function replaceAll(s, find, repl, caseOff, byChar) {
if (arguments.length<2)
return false;
var destDel = ! repl; // If destDel delete all keys from target
var isString = !! byChar; // If byChar, replace set of characters
if (typeof find !== typeof repl && ! destDel)
return false;
if (isString && (typeof find !== "string"))
return false;
if (! isString && (typeof find === "string")) {
return s.split(find).join(destDel ? "" : repl);
}
if ((! isString) && (! Array.isArray(find) ||
(! Array.isArray(repl) && ! destDel)))
return false;
// If destOne replace all strings/characters by just one element
var destOne = destDel ? false : (repl.length === 1);
// Generally source and destination should have the same size
if (! destOne && ! destDel && find.length !== repl.length)
return false
var prox, sUp, findUp, i, done;
if (caseOff) { // Case insensitive
// Working with uppercase keys and target
sUp = s.toUpperCase();
if (isString)
findUp = find.toUpperCase()
else
findUp = find.map(function(el) {
return el.toUpperCase();
});
}
else { // Case sensitive
sUp = s;
findUp = find.slice(); // Clone array/string
}
done = new Array(find.length); // Size: number of keys
done.fill(null);
var pos = 0; // Initial position in target s
var r = ""; // Initial result
var aux, winner;
while (pos < s.length) { // Scanning the target
prox = Number.MAX_SAFE_INTEGER;
winner = -1; // No winner at the start
for (i=0; i<findUp.length; i++) // Find next occurence for each string
if (done[i]!==-1) { // Key still alive
// Never search for the word/char or is over?
if (done[i] === null || done[i] < pos) {
aux = sUp.indexOf(findUp[i], pos);
done[i] = aux; // Save the next occurrence
}
else
aux = done[i] // Restore the position of last search
if (aux < prox && aux !== -1) { // If next occurrence is minimum
winner = i; // Save it
prox = aux;
}
} // Not done
if (winner === -1) { // No matches forward
r += s.slice(pos);
break;
} // No winner
// Found the character or string key in the target
i = winner; // Restore the winner
r += s.slice(pos, prox); // Update piece before the match
// Append the replacement in target
if (! destDel)
r += repl[destOne ? 0 : i];
pos = prox + (isString ? 1 : findUp[i].length); // Go after match
} // Loop
return r; // Return the resulting string
}
文档如下:
replaceAll Syntax ====== replaceAll(s, find, [repl, caseOff, byChar) Parameters ========== "s" is a string target of replacement. "find" can be a string or array of strings. "repl" should be the same type than "find" or empty If "find" is a string, it is a simple replacement for all "find" occurrences in "s" by string "repl" If "find" is an array, it will replaced each string in "find" that occurs in "s" for corresponding string in "repl" array. The replace specs are independent: A replacement part cannot be replaced again. If "repl" is empty all "find" occurrences in "s" will be deleted. If "repl" has only one character or element, all occurrences in "s" will be replaced for that one. "caseOff" is true if replacement is case insensitive (default is FALSE) "byChar" is true when replacement is based on set of characters. Default is false If "byChar", it will be replaced in "s" all characters in "find" set of characters for corresponding character in "repl" set of characters Return ====== The function returns the new string after the replacement.
公平地说,我运行的基准测试没有参数测试。
以下是我的测试集,使用 Node.js:
function l() {
return console.log.apply(null, arguments);
}
var k = 0;
l(++k, replaceAll("banana is a ripe fruit harvested near the river",
["ri", "nea"], ["do", "fa"])); // 1
l(++k, replaceAll("banana is a ripe fruit harvested near the river",
["ri", "nea"], ["do"])); // 2
l(++k, replaceAll("banana is a ripe fruit harvested near the river",
["ri", "nea"])); // 3
l(++k, replaceAll("banana is a ripe fruit harvested near the river",
"aeiou", "", "", true)); // 4
l(++k, replaceAll("banana is a ripe fruit harvested near the river",
"aeiou", "a", "", true)); // 5
l(++k, replaceAll("banana is a ripe fruit harvested near the river",
"aeiou", "uoiea", "", true)); // 6
l(++k, replaceAll("banana is a ripe fruit harvested near the river",
"aeiou", "uoi", "", true)); // 7
l(++k, replaceAll("banana is a ripe fruit harvested near the river",
["ri", "nea"], ["do", "fa", "leg"])); // 8
l(++k, replaceAll("BANANA IS A RIPE FRUIT HARVESTED NEAR THE RIVER",
["ri", "nea"], ["do", "fa"])); // 9
l(++k, replaceAll("BANANA IS A RIPE FRUIT HARVESTED NEAR THE RIVER",
["ri", "nea"], ["do", "fa"], true)); // 10
return;
结果如下:
1 '香蕉是一种在多佛附近收获的优质水果'
2 '香蕉是一种在多佛附近收获的优质水果'
3 '香蕉是一种在多佛附近收获的优质水果'
4 'bnn s rp frt hrvstd nr th rvr'
5 '香蕉是一种在河边收获的成熟水果'
6 'bununu 是一种在河边收获的成熟水果'
7 false
8 false
9 '香蕉是一种在河边收获的优质水果'
10 '香蕉是一种在多佛附近收获的优质水果'
解决方案 30:
2019 年 11 月,JavaScript 添加了一项新功能string.prototype.replaceAll()
。
目前只有Babel支持,但未来可能会在所有浏览器中实现。更多信息请阅读这里。