274

我正在尝试用多个其他单词替换字符串中的多个单词。字符串是“我有一只猫、一只狗和一只山羊”。

但是,这不会产生“我有一只狗、一只山羊和一只猫”,而是会产生“我有一只猫、一只猫和一只猫”。是否可以在 JavaScript 中同时用多个其他字符串替换多个字符串,从而产生正确的结果?

var str = "I have a cat, a dog, and a goat.";
str = str.replace(/cat/gi, "dog");
str = str.replace(/dog/gi, "goat");
str = str.replace(/goat/gi, "cat");

//this produces "I have a cat, a cat, and a cat"
//but I wanted to produce the string "I have a dog, a goat, and a cat".
4

27 回答 27

551

具体解决方案

您可以使用一个函数来替换每个函数。

var str = "I have a cat, a dog, and a goat.";
var mapObj = {
   cat:"dog",
   dog:"goat",
   goat:"cat"
};
str = str.replace(/cat|dog|goat/gi, function(matched){
  return mapObj[matched];
});

jsfiddle 示例

概括它

如果您想动态维护正则表达式并将未来的交换添加到地图中,您可以这样做

new RegExp(Object.keys(mapObj).join("|"),"gi"); 

生成正则表达式。那么它看起来像这样

var mapObj = {cat:"dog",dog:"goat",goat:"cat"};

var re = new RegExp(Object.keys(mapObj).join("|"),"gi");
str = str.replace(re, function(matched){
  return mapObj[matched];
});

要添加或更改更多替换,您只需编辑地图即可。 

摆弄动态正则表达式

使其可重用

如果您希望这是一个通用模式,您可以将其拉出到这样的函数中

function replaceAll(str,mapObj){
    var re = new RegExp(Object.keys(mapObj).join("|"),"gi");

    return str.replace(re, function(matched){
        return mapObj[matched.toLowerCase()];
    });
}

因此,您可以将 str 和您想要的替换映射传递给函数,它会返回转换后的字符串。

摆弄功能

要确保 Object.keys 在旧浏览器中工作,请添加一个 polyfill,例如来自MDNEs5

于 2013-03-24T21:26:09.917 回答
26

作为答案:

寻找最新的答案

如果您在当前示例中使用“单词”,则可以使用非捕获组扩展Ben McCormick\b的答案,并在左侧和右侧添加单词边界以防止部分匹配。

\b(?:cathy|cat|catch)\b
  • \b防止部分匹配的单词边界
  • (?:非捕获组
    • cathy|cat|catch匹配其中一种选择
  • )关闭非捕获组
  • \b防止部分匹配的单词边界

原始问题的示例:

let str = "I have a cat, a dog, and a goat.";
const mapObj = {
  cat: "dog",
  dog: "goat",
  goat: "cat"
};
str = str.replace(/\b(?:cat|dog|goat)\b/gi, matched => mapObj[matched]);
console.log(str);

评论中的示例似乎效果不佳:

let str = "I have a cat, a catch, and a cathy.";
const mapObj = {
  cathy: "cat",
  cat: "catch",
  catch: "cathy"

};
str = str.replace(/\b(?:cathy|cat|catch)\b/gi, matched => mapObj[matched]);
console.log(str);

于 2021-05-03T19:24:06.750 回答
16

使用编号的项目以防止再次更换。例如

let str = "I have a %1, a %2, and a %3";
let pets = ["dog","cat", "goat"];

然后

str.replace(/%(\d+)/g, (_, n) => pets[+n-1])

它是如何工作的:- %\d+ 查找 % 之后的数字。括号捕获数字。

这个数字(作为字符串)是 lambda 函数的第二个参数 n。

+n-1 将字符串转换为数字,然后减去 1 以索引 pets 数组。

然后将 %number 替换为数组索引处的字符串。

/g 导致使用每个数字重复调用 lambda 函数,然后将其替换为数组中的字符串。

在现代 JavaScript 中:-

replace_n=(str,...ns)=>str.replace(/%(\d+)/g,(_,n)=>ns[n-1])
于 2018-05-18T12:39:32.010 回答
13

在这种情况下,这可能无法满足您的确切需求,但我发现这是一种替换字符串中多个参数的有用方法,作为一种通用解决方案。它将替换参数的所有实例,无论它们被引用多少次:

String.prototype.fmt = function (hash) {
        var string = this, key; for (key in hash) string = string.replace(new RegExp('\\{' + key + '\\}', 'gm'), hash[key]); return string
}

您可以按如下方式调用它:

var person = '{title} {first} {last}'.fmt({ title: 'Agent', first: 'Jack', last: 'Bauer' });
// person = 'Agent Jack Bauer'
于 2013-03-24T23:59:18.907 回答
6

使用Array.prototype.reduce()

const arrayOfObjects = [
  { plants: 'men' },
  { smart:'dumb' },
  { peace: 'war' }
]
const sentence = 'plants are smart'

arrayOfObjects.reduce(
  (f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence
)

// as a reusable function
const replaceManyStr = (obj, sentence) => obj.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence)

const result = replaceManyStr(arrayOfObjects , sentence1)

例子

// /////////////    1. replacing using reduce and objects

// arrayOfObjects.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence)

// replaces the key in object with its value if found in the sentence
// doesn't break if words aren't found

// Example

const arrayOfObjects = [
  { plants: 'men' },
  { smart:'dumb' },
  { peace: 'war' }
]
const sentence1 = 'plants are smart'
const result1 = arrayOfObjects.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence1)

console.log(result1)

// result1: 
// men are dumb


// Extra: string insertion python style with an array of words and indexes

// usage

// arrayOfWords.reduce((f, s, i) => `${f}`.replace(`{${i}}`, s), sentence)

// where arrayOfWords has words you want to insert in sentence

// Example

// replaces as many words in the sentence as are defined in the arrayOfWords
// use python type {0}, {1} etc notation

// five to replace
const sentence2 = '{0} is {1} and {2} are {3} every {5}'

// but four in array? doesn't break
const words2 = ['man','dumb','plants','smart']

// what happens ?
const result2 = words2.reduce((f, s, i) => `${f}`.replace(`{${i}}`, s), sentence2)

console.log(result2)

// result2: 
// man is dumb and plants are smart every {5}

// replaces as many words as are defined in the array
// three to replace
const sentence3 = '{0} is {1} and {2}'

// but five in array
const words3 = ['man','dumb','plant','smart']

// what happens ? doesn't break
const result3 = words3.reduce((f, s, i) => `${f}`.replace(`{${i}}`, s), sentence3)

console.log(result3)

// result3: 
// man is dumb and plants

于 2019-06-18T03:07:03.713 回答
5

这对我有用:

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.replace(new RegExp(search, 'g'), replacement);
};

function replaceAll(str, map){
    for(key in map){
        str = str.replaceAll(key, map[key]);
    }
    return str;
}

//testing...
var str = "bat, ball, cat";
var map = {
    'bat' : 'foo',
    'ball' : 'boo',
    'cat' : 'bar'
};
var new = replaceAll(str, map);
//result: "foo, boo, bar"
于 2016-02-16T11:50:04.283 回答
4

使用我的replace-once包,您可以执行以下操作:

const replaceOnce = require('replace-once')

var str = 'I have a cat, a dog, and a goat.'
var find = ['cat', 'dog', 'goat']
var replace = ['dog', 'goat', 'cat']
replaceOnce(str, find, replace, 'gi')
//=> 'I have a dog, a goat, and a cat.'
于 2018-03-04T18:14:04.523 回答
3

以防万一有人想知道为什么原始海报的解决方案不起作用:

var str = "I have a cat, a dog, and a goat.";

str = str.replace(/cat/gi, "dog");
// now str = "I have a dog, a dog, and a goat."

str = str.replace(/dog/gi, "goat");
// now str = "I have a goat, a goat, and a goat."

str = str.replace(/goat/gi, "cat");
// now str = "I have a cat, a cat, and a cat."
于 2017-07-03T10:58:10.177 回答
2

此解决方案可以调整为仅替换整个单词- 例如,在搜索“cat”时不会找到“catch”、“ducat”或“locator”。这可以通过对正则表达式中每个单词之前和之后的单词字符使用负向后(?<!\w)查找和负向前查找来完成:(?!\w)

(?<!\w)(cathy|cat|ducat|locator|catch)(?!\w)

JSFiddle 演示:http: //jsfiddle.net/mfkv9r8g/1/

于 2021-05-04T08:40:58.217 回答
1
    var str = "I have a cat, a dog, and a goat.";

    str = str.replace(/goat/i, "cat");
    // now str = "I have a cat, a dog, and a cat."

    str = str.replace(/dog/i, "goat");
    // now str = "I have a cat, a goat, and a cat."

    str = str.replace(/cat/i, "dog");
    // now str = "I have a dog, a goat, and a cat."
于 2019-06-17T13:10:29.757 回答
1

笔记!

如果您使用的是动态提供的映射,那么这里的解决方案都不够用!

在这种情况下,有两种方法可以解决这个问题,(1)使用拆分连接技术,(2)使用带有特殊字符转义技术的正则表达式。

  1. 这是一种拆分连接技术,比另一种快得多(至少快 50%):

var str = "I have {abc} a c|at, a d(og, and a g[oat] {1} {7} {11."
var mapObj = {
   'c|at': "d(og",
   'd(og': "g[oat",
   'g[oat]': "c|at",
};
var entries = Object.entries(mapObj);
console.log(
  entries
    .reduce(
      // Replace all the occurrences of the keys in the text into an index placholder using split-join
      (_str, [key], i) => _str.split(key).join(`{${i}}`), 
      // Manipulate all exisitng index placeholder -like formats, in order to prevent confusion
      str.replace(/\{(?=\d+\})/g, '{-')
    )
    // Replace all index placeholders to the desired replacement values
    .replace(/\{(\d+)\}/g, (_,i) => entries[i][1])
    // Undo the manipulation of index placeholder -like formats
    .replace(/\{-(?=\d+\})/g, '{')
);

  1. 这个是正则表达式特殊字符转义技术,它也有效,但要慢得多:

var str = "I have a c|at, a d(og, and a g[oat]."
var mapObj = {
   'c|at': "d(og",
   'd(og': "g[oat",
   'g[oat]': "c|at",
};
console.log(
  str.replace(
    new RegExp(
      // Convert the object to array of keys
      Object.keys(mapObj)
        // Escape any special characters in the search key
        .map(key => key.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'))
        // Create the Regex pattern
        .join('|'), 
      // Additional flags can be used. Like `i` - case-insensitive search
      'g'
    ), 
    // For each key found, replace with the appropriate value
    match => mapObj[match]
  )
);

后者的优点是它也可以与不区分大小写的搜索一起使用。

于 2021-04-30T17:13:32.537 回答
1

用户常规函数定义要替换的模式,然后使用替换函数处理输入字符串,

var i = new RegExp('"{','g'),
    j = new RegExp('}"','g'),
    k = data.replace(i,'{').replace(j,'}');
于 2017-08-18T07:08:55.233 回答
1
/\b(cathy|cat|catch)\b/gi

“运行代码片段”以查看以下结果:

var str = "I have a cat, a catch, and a cathy.";
var mapObj = {
   cathy:"cat",
   cat:"catch",
   catch:"cathy"
};
str = str.replace(/\b(cathy|cat|catch)\b/gi, function(matched){
  return mapObj[matched];
});

console.log(str);

于 2021-05-01T02:15:15.623 回答
1

您可以使用分隔符查找和替换字符串。

var obj = {
  'firstname': 'John',
  'lastname': 'Doe'
}

var text = "My firstname is {firstname} and my lastname is {lastname}"

alert(mutliStringReplace(obj,text))

function mutliStringReplace(object, string) {
      var val = string
      var entries = Object.entries(object);
      entries.forEach((para)=> {
          var find = '{' + para[0] + '}'
          var regExp = new RegExp(find,'g')
       val = val.replace(regExp, para[1])
    })
  return val;
}

于 2019-11-14T17:40:50.347 回答
1

试试我的解决方案。随时改进

function multiReplace(strings, regex, replaces) {
  return str.replace(regex, function(x) {
    // check with replaces key to prevent error, if false it will return original value
    return Object.keys(replaces).includes(x) ? replaces[x] : x;
  });
}
var str = "I have a Cat, a dog, and a goat.";
//(json) use value to replace the key
var replaces = {
  'Cat': 'dog',
  'dog': 'goat',
  'goat': 'cat',
}
console.log(multiReplace(str, /Cat|dog|goat/g, replaces))

于 2021-07-02T04:36:30.213 回答
0
String.prototype.replaceSome = function() {
    var replaceWith = Array.prototype.pop.apply(arguments),
        i = 0,
        r = this,
        l = arguments.length;
    for (;i<l;i++) {
        r = r.replace(arguments[i],replaceWith);
    }
    return r;
}

/* 字符串的 replaceSome 方法,它接受我们想要的多个参数,并将所有参数替换为我们指定的最后一个参数 2013 CopyRights 为:Max Ahmed 这是一个示例:

var string = "[hello i want to 'replace x' with eat]";
var replaced = string.replaceSome("]","[","'replace x' with","");
document.write(string + "<br>" + replaced); // returns hello i want to eat (without brackets)

*/

jsFiddle:http: //jsfiddle.net/CPj89/

于 2013-12-01T13:34:16.553 回答
0

我写了这个 npm 包 stringinject https://www.npmjs.com/package/stringinject它允许您执行以下操作

var string = stringInject("this is a {0} string for {1}", ["test", "stringInject"]);

它将用数组项替换 {0} 和 {1} 并返回以下字符串

"this is a test string for stringInject"

或者您可以使用对象键和值替换占位符,如下所示:

var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });

"My username is tjcafferkey on Github" 
于 2017-07-19T16:06:46.263 回答
0

通过使用原型函数,我们可以通过传递带有键和值以及可替换文本的对象来轻松替换

String.prototype.replaceAll=function(obj,keydata='key'){
 const keys=keydata.split('key');
 return Object.entries(obj).reduce((a,[key,val])=> a.replace(`${keys[0]}${key}${keys[1]}`,val),this)
}

const data='hids dv sdc sd ${yathin} ${ok}'
console.log(data.replaceAll({yathin:12,ok:'hi'},'${key}'))

于 2020-07-02T09:31:59.837 回答
0

const str = 'Thanks for contributing an answer to Stack Overflow!'
    const substr = ['for', 'to']

    function boldString(str, substr) {
        let boldStr
        boldStr = str
        substr.map(e => {
                const strRegExp = new RegExp(e, 'g');
                boldStr= boldStr.replace(strRegExp, `<strong>${e}</strong>`);
            }
        )
        return boldStr
}

于 2021-12-14T10:16:17.157 回答
0

所有解决方案都工作得很好,除非应用于闭包的编程语言(例如 Coda、Excel、Spreadsheet's REGEXREPLACE)。

下面我的两个原始解决方案仅使用 1 个连接和 1 个正则表达式。

方法#1:查找替换值

这个想法是如果它们不在字符串中,则附加替换值。然后,使用单个正则表达式,我们执行所有需要的替换:

var str = "I have a cat, a dog, and a goat.";
str = (str+"||||cat,dog,goat").replace(
   /cat(?=[\s\S]*(dog))|dog(?=[\s\S]*(goat))|goat(?=[\s\S]*(cat))|\|\|\|\|.*$/gi, "$1$2$3");
document.body.innerHTML = str;

说明:

  • cat(?=[\s\S]*(dog))意味着我们寻找“猫”。如果匹配,则正向查找将捕获“dog”作为组 1,否则捕获“”。
  • 对于将“goat”捕获为第 2 组的“dog”和将“cat”捕获为第 3 组的“goat”也是如此。
  • 我们替换为"$1$2$3"(所有三个组的串联),对于上述情况之一,它始终是“狗”、“猫”或“山羊”
  • 如果我们手动将替换附加到字符串 like str+"||||cat,dog,goat",我们也会通过匹配来删除它们\|\|\|\|.*$,在这种情况下,替换"$1$2$3"将评估为“”,即空字符串。

方法#2:查找替换对

方法 #1 的一个问题是它一次不能超过 9 个替换,这是反向传播组的最大数量。方法 #2 声明不要仅附加替换值,而是直接附加替换:

var str = "I have a cat, a dog, and a goat.";
str = (str+"||||,cat=>dog,dog=>goat,goat=>cat").replace(
   /(\b\w+\b)(?=[\s\S]*,\1=>([^,]*))|\|\|\|\|.*$/gi, "$2");
document.body.innerHTML = str;

说明:

  • (str+"||||,cat=>dog,dog=>goat,goat=>cat")是我们如何将替换映射附加到字符串的末尾。
  • (\b\w+\b)声明“捕获任何单词”,可以用“(cat|dog|goat) 或其他任何内容替换。
  • (?=[\s\S]*...)是一个正向查找,通常会一直到文档的末尾,直到替换映射之后。
    • ,\1=>意思是“你应该在逗号和右箭头之间找到匹配的词”
    • ([^,]*)表示“匹配此箭头之后的任何内容,直到下一个逗号或文档结尾”
  • |\|\|\|\|.*$是我们如何删除替换地图。
于 2020-08-31T18:33:39.733 回答
0

为此,您可以使用https://www.npmjs.com/package/union-replacer 。它基本上是一个string.replace(regexp, ...)对应物,它允许一次进行多次替换,同时保留string.replace(...).

披露:我是作者。该库的开发是为了支持更复杂的用户可配置替换,它解决了所有有问题的问题,如捕获组、反向引用和回调函数替换。

上面的解决方案对于精确的字符串替换来说已经足够好了。

于 2019-11-16T15:19:34.390 回答
0
<!DOCTYPE html>
<html>
<body>



<p id="demo">Mr Blue 
has a           blue house and a blue car.</p>

<button onclick="myFunction()">Try it</button>

<script>
function myFunction() {
    var str = document.getElementById("demo").innerHTML;
    var res = str.replace(/\n| |car/gi, function myFunction(x){

if(x=='\n'){return x='<br>';}
if(x==' '){return x='&nbsp';}
if(x=='car'){return x='BMW'}
else{return x;}//must need



});

    document.getElementById("demo").innerHTML = res;
}
</script>

</body>
</html>
于 2016-08-13T10:42:03.903 回答
0

你可以试试这个。买不聪明。

var str = "I have a cat, a dog, and a goat.";
console.log(str);
str = str.replace(/cat/gi, "XXX");
console.log(str);
str = str.replace(/goat/gi, "cat");
console.log(str);
str = str.replace(/dog/gi, "goat");
console.log(str);
str = str.replace(/XXX/gi, "dog");              
console.log(str);
输出:我有一只狗、一只山羊和一只猫。

于 2021-05-07T09:57:51.510 回答
0

我们还可以使用 split() 和 join() 方法:

var str = "I have a cat, a dog, and a goat.";

str=str.split("cat").map(x => {return x.split("dog").map(y => {return y.split("goat").join("cat");}).join("goat");}).join("dog");

console.log(str);

于 2021-05-03T14:22:28.823 回答
0

一种可能的解决方案是使用映射器表达式函数。

const regex = /(?:cat|dog|goat)/gmi;
const str = `I have a cat, a dog, and a goat.`;

let mapper = (key) => {
  switch (key) {
    case "cat":
      return "dog"
    case "dog":
      return "goat";
    case "goat":
      return "cat"
  }
}
let result = str.replace(regex, mapper);

console.log('Substitution result: ', result);
//Substitution result1:  I have a dog, a goat, and a cat.
于 2021-05-06T19:02:48.027 回答
-1

我对@BenMcCormicks 进行了一些扩展。他适用于常规字符串,但如果我有转义字符或通配符,则不会。这就是我所做的

str = "[curl] 6: blah blah 234433 blah blah";
mapObj = {'\\[curl] *': '', '\\d: *': ''};


function replaceAll (str, mapObj) {

    var arr = Object.keys(mapObj),
        re;

    $.each(arr, function (key, value) {
        re = new RegExp(value, "g");
        str = str.replace(re, function (matched) {
            return mapObj[value];
        });
    });

    return str;

}
replaceAll(str, mapObj)

返回“废话 234433 废话”

这样它将匹配 mapObj 中的键而不是匹配的单词'

于 2014-11-17T16:33:02.633 回答
-5

使用Jquery的解决方案(首先包含此文件):用多个其他字符串替换多个字符串:

var replacetext = {
    "abc": "123",
    "def": "456"
    "ghi": "789"
};

$.each(replacetext, function(txtorig, txtnew) {
    $(".eng-to-urd").each(function() {
        $(this).text($(this).text().replace(txtorig, txtnew));
    });
});
于 2018-01-16T08:08:05.280 回答