简体   繁体   English

替换字符串中的值(如果它们存在于变量数组中)

[英]Replace values from a string if they are present in an array of variables

Having the following array of objects:具有以下对象数组:

const variables = [
  { name: '%NAME%', value: 'joe' },
  { name: '%EMAIL%', value: '%NAME%@mail.com' },
  { name: '%HOBBY%', value: 'tennis' }
];

And the input string:和输入字符串:

const inputString = `Hi, my name is %NAME%, I like %HOBBY%, you can contact me at %EMAIL%`;

The function should take as arguments variables and inputString and return the following sting: function 应采用 arguments variablesinputString并返回以下字符串:

'Hi, my name is joe, I like tennis, you can contact me at joe@mail.com'

Here is the function so far:到目前为止,这是 function:

function doMagic(variables, inputString) {
  let output = inputString;
  for (let i = 0; i < variables.length; i++) {
     output = inputString.replace(variables[i].name, variables[i].value);
  }
  return output;
}

Unfortunatelly, this only finds one occurrence, in case there are more, and it doesn't go into nested variables, like %EMAIL% .不幸的是,这只会发现一次,以防万一有更多,并且它不会将 go 放入嵌套变量中,例如%EMAIL%

Any ideas to improve?有什么改进的想法吗?

We can do a regex replacement with the help of a callback function:我们可以在回调 function 的帮助下进行正则表达式替换:

 var variables = [ {name: '%NAME%', value: 'joe'}, {name: '%EMAIL%', value: 'joe@mail.com'}, {name: '%HOBBY%', value: 'tennis'} ]; var regex = new RegExp("(" + variables.map(x => x.name).join("|") + ")", "g"); var inputString = "Hi, my name is %NAME%, I like %HOBBY%, you can contact me at %EMAIL%"; var output = inputString.replace(regex, (m) => { return variables.filter(x => x.name == m)[0].value; }); console.log(output);

The strategy here is to first build a regex alternation of names from the map. We do a global regex search for these names in the input string.这里的策略是首先从 map 构建名称的正则表达式替换。我们对输入字符串中的这些名称进行全局正则表达式搜索。 For each match, the callback function replaces the name with the value from the map.对于每个匹配项,回调 function 会将名称替换为 map 中的值。

You could do a recursive call until there are no variables left in the string您可以进行递归调用,直到字符串中没有剩余变量

 const variables = [ { name: '%NAME%', value: 'joe' }, { name: '%EMAIL%', value: '%NAME%@mail.com' }, { name: '%HOBBY%', value: 'tennis' }, ]; const inputString = `Hi, my name is %NAME%', I like %HOBBY%, you can contact me at %EMAIL%`; function doMagic(variables, inputString) { let output = inputString; for (let i = 0; i < variables.length; i++) { output = output.replace(variables[i].name, variables[i].value); } for (let i = 0; i < variables.length; i++) { if (output.includes(variables[i].name)) { output = doMagic(variables, output); } } return output; } console.log(doMagic(variables, inputString));

Looping backwards through the array, and using replaceAll() should do the trick.向后遍历数组,并使用 replaceAll() 应该可以解决问题。

 const variables = [ { name: '%NAME%', value: 'joe' }, { name: '%EMAIL%', value: '%NAME%@mail.com' }, { name: '%HOBBY%', value: 'tennis' }, ]; const inputString = `Hi, my name is %NAME%', I like %HOBBY%, you can contact me at %EMAIL%`; function doMagic(variables, inputString) { let output = inputString; variables.slice().reverse().forEach(variable => { output = output.replaceAll(variable.name, variable.value); }) return output; } console.log(doMagic(variables, inputString));

Using regex and while(regex.test.output()) also does the trick.使用 regex 和 while(regex.test.output()) 也可以解决问题。

 const variables = [ { name: '%NAME%', value: 'joe' }, { name: '%EMAIL%', value: '%NAME%@mail.com' }, { name: '%HOBBY%', value: 'tennis' }, ]; const inputString = `Hi, my name is %NAME%', I like %HOBBY%, you can contact me at %EMAIL%`; function doMagic(variables, inputString) { const regex = new RegExp("(" + variables.map(x => x.name).join("|") + ")", "g"); let output = inputString; while (regex.test(output)) { output = output.replace(regex, m => { return variables.filter(x => x.name == m)[0].value; }) } return output; } console.log(doMagic(variables, inputString));

You can use replaceAll method to replace all the occurrence and loop twice.您可以使用 replaceAll 方法替换所有出现并循环两次。

function doMagic(variables, inputString) {
  let output = inputString;
  for (let i = 0; i < variables.length; i++) {
     output = output.replaceAll(variables[i].name, variables[i].value);
  }
  for (let i = 0; i < variables.length; i++) {
     output = output.replaceAll(variables[i].name, variables[i].value);
  }
  return output;
}

Issues.问题。

  • You have not updated inputString after string replace.字符串替换后您还没有更新inputString

I have made use of below logic.我使用了以下逻辑。

  • Loop through variables first.首先循环遍历变量。
  • Replace the values if any of the value consist of node from variable array itself (in our case replace %NAME%@mail.com as joe@mail.com)如果任何值由变量数组本身的节点组成,则替换值(在我们的例子中,将 %NAME%@mail.com 替换为 joe@mail.com)
  • Use this replaced array to perform replacement of string values from inputString .使用这个替换数组来替换inputString中的字符串值。
  • Use replaceAll instead of replace to handle multiple ovvurance of same variable.使用replaceAll而不是replace来处理同一变量的多个进化。

 const variables = [ { name: '%NAME%', value: 'joe' }, { name: '%EMAIL%', value: '%NAME%@mail.com' }, { name: '%HOBBY%', value: 'tennis' } ]; const inputString = `Hi, my name is %NAME%', I like %HOBBY%, you can contact me at %EMAIL%`; function doMagic(variables, inputString) { let output = inputString; // First replace variables for (let i = 0; i < variables.length; i++) { const node = variables.find(item => item.value.includes(variables[i].name)); if (node) { node.value = node.value.replaceAll(variables[i].name, variables[i].value); } } for (let i = 0; i < variables.length; i++) { output = output.replaceAll(variables[i].name, variables[i].value); } return output; } console.log(doMagic(variables, inputString))

My solution with use "reduce"我使用“减少”的解决方案

 const variables = [ { name: "%NAME%", value: "joe" }, { name: "%EMAIL%", value: "%NAME%@mail.com" }, { name: "%HOBBY%", value: "tennis" } ]; const inputString = "Hi, my name is %NAME%, I like %HOBBY%, you can contact me at %EMAIL%"; function doMagic(string, variables) { const replaceVar = (s, v) => v.reduce((prev = "", { name, value }) => prev.replace(name, value), s); const fixedVariables = variables.map((v) => ({...v, value: replaceVar(v.value, variables) })); return replaceVar(string, fixedVariables); } console.log(doMagic(inputString, variables));

Also if you want, you can modify my code to prototype, like this:另外,如果您愿意,可以将我的代码修改为原型,如下所示:

 const inputString = "Hi, my name is %NAME%, I like %HOBBY%, you can contact me at %EMAIL%"; String.prototype.doMagic = function (variables) { const replaceVar = (s, v) => v.reduce((prev = "", { name, value }) => prev.replace(name, value), s); const fixedVariables = variables.map(({ value, ...rest }) => ({...rest, value: replaceVar(value, variables) })); return replaceVar(this, fixedVariables); }; console.log( inputString.doMagic([ { name: "%NAME%", value: "joe" }, { name: "%EMAIL%", value: "%NAME%@mail.com" }, { name: "%HOBBY%", value: "tennis" } ]) )

Bit lengthy version, But if you need to do in one iteration, iterate over each character and when you get second % (means ending) then look for replacement of string.有点冗长的版本,但如果你需要在一次迭代中完成,迭代每个字符,当你得到第二个 % (意味着结束)时,然后寻找字符串的替换。

 const variables = [ { name: "%NAME%", value: "joe" }, { name: "%EMAIL%", value: "%NAME%@mail.com" }, { name: "%HOBBY%", value: "tennis" }, ]; const inputString = `Hi, my name is %NAME%, I like %HOBBY%, you can contact me at %EMAIL%`; const cache = variables.reduce((acc, { name, value }) => ({...acc, [name]: value, }), {}); const myReplace = (str) => { let newString = ""; let count = 0; let last = 0; let i; for (i = 0; i < str.length; i++) { if (str[i] === "%") { if (count === 0) { newString = `${newString}${str.slice(last, i)}`; count += 1; last = i; } else { newString = `${newString}${myReplace(cache[str.slice(last, i + 1)])}`; count = 0; last = i + 1; } } } newString = `${newString}${str.slice(last, i)}`; return newString; }; console.log(myReplace(inputString))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM