我试图用多个其他单词替换字符串中的多个单词。字符串是“我有一只猫,一只狗和一只山羊。”
然而,这并不会产生“我有一只狗、一只山羊和一只猫”,而是产生“我有一只猫、一只猫和一只猫”。是否有可能在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".
作为对以下问题的回答:
寻找最新的答案
如果在当前示例中使用“words”,则可以使用非捕获组扩展Ben McCormick的答案,并在左侧和右侧添加单词边界\b以防止部分匹配。
\b(?:cathy|cat|catch)\b
防止部分匹配的单词边界
(?:非捕获组
Cathy |cat|catch匹配其中一个选项
)关闭非捕获组
防止部分匹配的单词边界
原问题的例子:
let str = "我有一只猫,一只狗和一只山羊。";
const mapObj = {
猫:“狗”,
狗:“山羊”,
山羊:“猫”
};
str = str.replace(/\b(?:猫|狗|山羊)\b/gi, matched => mapObj[matched]);
console.log (str);
评论中的例子似乎并没有很好地工作:
let str = "I have a cat, a catch and a cathy.";
const mapObj = {
凯茜:“猫”,
猫:“抓”,
抓住:“凯蒂”
};
str = str.replace(/\b(?:cathy|cat|catch)\b/gi, matched => mapObj[matched]);
console.log (str);
我修改了本·麦考密克的答案以配合你的新测试用例。
我只是在正则表达式中添加了单词边界:
/\b(cathy|cat|catch)\b/gi
“运行代码片段”可以看到下面的结果:
var str = "我有一只猫,一个catch,和一个cathy.";
var mapObj = {
凯茜:“猫”,
猫:“抓”,
抓住:“凯蒂”
};
STR = STR .replace(/\b(cathy|cat|catch)\b/gi, function(matched){
返回mapObj(匹配);
});
console.log (str);
我扩展了一下@本麦考密克斯。他的工作规则字符串,但不如果我转义字符或通配符。我是这么做的
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)
返回"blah blah 234433 blah blah"
这样它将匹配mapObj中的键,而不是匹配的单词'
通过使用原型函数,我们可以通过传递对象的键和值以及可替换的文本轻松地进行替换
String.prototype.replaceAll =函数(obj keydata =“关键”){
const键= keydata.split(关键);
返回Object.entries (obj) .reduce((,(关键,val)) = > a.replace(“${键[0]}${关键}${键[1]}',val),)
}
Const data=' hidden dv SDC sd ${yathin} ${ok}'
console.log (data.replaceAll ({yathin: 12,好的:“嗨”},“${关键}”))
我写了这个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"
注意!
如果您正在使用动态提供的映射,这里的解决方案都不够!
在这种情况下,有两种解决方法:(1)使用分割连接技术,(2)使用正则表达式和特殊字符转义技术。
这是一个分割连接技术,它比另一个快得多(至少快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, '{')
);
这一个,是Regex特殊字符转义技术,它也有用,但慢得多:
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]
)
);
后者的优点是,它也可以用于不区分大小写的搜索。