用多个其他字符串替换多个字符串

IT技术 javascript node.js regex string replace
2021-02-07 16:34:37

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

然而,这不会产生“我有一只狗、一只山羊和一只猫”,而是产生“我有一只猫、一只猫和一只猫”。是否可以在 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".
6个回答

具体解决方案

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

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

我不确定是否可以使用此函数替换所有类型的字符串,因为 JavaScript 字符串中允许的字符与 JavaScript 标识符中允许的字符(例如此处使用的键)不同.
2021-03-12 16:34:37
您可能想要转义正则表达式的键:Object.keys(mapObj).map(key => key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('|')受到这个答案的启发
2021-03-15 16:34:37
它确实很好用。我成功地使用此解决方案(“特定”解决方案)将英语数字符号更改为欧洲数字符号(24,973.56 到 24.973,56),使用map={'.': ',', ',': '.'}和 regex /\.|,/g
2021-03-16 16:34:37
您可以使用任意字符串作为 javascript 属性。应该没关系。您只是不能将.符号与所有这些属性一起使用。括号表示法适用于任何字符串。
2021-03-25 16:34:37
我喜欢这个解决方案,但我不得不替换return mapObj[matched.toLowerCase()];为 ,return mapObj[matched];因为我在mapObj.
2021-04-01 16:34:37

作为对以下问题的回答:

寻找最新的答案

如果您在当前示例中使用“单词”,您可以使用非捕获组扩展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-03-24 16:34:37

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

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])
有趣的。你能解释一下替换函数中的逻辑吗?
2021-03-17 16:34:37
I have a %11, a %21, and a %31一旦我们需要最终结果,这对于文本将无法正常工作I have a dog1, a cat1, and a goat1
2021-03-31 16:34:37

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

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'
仅当您的密钥不包含任何特殊的正则表达式字符时,这才有效。否则,它将返回错误或更糟的是,一个意外的行为。例如:'abc'.fmt({'a(b':1})
2021-04-04 16:34:37

使用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

如果您希望替换所有给定的字符串,而不仅仅是第一个,请添加 g 标志:“const result1 = arrayOfObjects.reduce((f, s) => ${f}.replace(new RegExp(Object.keys(s)[ 0],'g'), s[Object.keys(s)[0]]), sentence1)"
2021-03-14 16:34:37
最佳答案。但是是否有理由使用${f}f 代替 f 作为累加值?
2021-03-20 16:34:37