Swap out values in a string if they match any of the variables in an array

Let's work with an array of objects:

const data = [
  { key: '%KEY1%', value: 'value1' },
  { key: '%KEY2%', value: '%KEY1% abc' },
  { key: '%KEY3%', value: 'xyz' }
];

Now, we have a string to process:

const inputText = `This is %KEY1%, also known as %KEY2%. Contact us at %KEY3%`;

The goal is to create a function that accepts data and inputText, and outputs the modified string:

'This is value1, also known as value1 abc. Contact us at xyz'

Here is the current implementation:

function processData(data, inputText) {
  let result = inputText;
  for (let index = 0; index < data.length; index++) {
     result = inputText.replace(data[index].key, data[index].value);
  }
  return result;
}

Unfortunately, this approach only replaces one occurrence and doesn't handle nested variables, like %KEY2%.

How would you enhance this functionality?

Answer №1

To achieve the desired result, you can loop through the array backwards and utilize the replaceAll() method.

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));

Another approach is to use regex and while-loop with regex.test(output()) to achieve the same outcome.

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));

Answer №2

To eliminate all variables within the string, consider using a recursive function until none are left.

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));

Answer №3

To perform a regex substitution using a callback function, we can follow this approach:

const placeholders = [
                   {key: '%NAME%', value: 'Alice'},
                   {key: '%EMAIL%', value: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dbb5b0b99ebeb2babffeafb6">[email protected]</a>'},
                   {key: '%AGE%', value: '30'}
                  ];
const regexPattern = new RegExp("(" + placeholders.map(item => item.key).join("|") + ")", "g");
const inputText = "Hello, my name is %NAME%, feel free to email me at %EMAIL%, I am %AGE% years old";
const updatedText = inputText.replace(regexPattern, (match) => {
    return placeholders.filter(item => item.key === match)[0].value;
});
console.log(updatedText);

The approach involves creating a regex pattern that combines all placeholder keys from the map. This pattern is then used to globally search for matches in the input text. For each match found, the corresponding value from the map is substituted using a callback function.

Answer №4

Solving the Problems.

  • Make sure to update the inputString after performing a string replacement.

The solution implemented follows these steps:

  • Iterate through the variables first.
  • If any value includes a node from the variable array, replace it (e.g. replace %NAME%@mail.com with [email protected])
  • Use the updated array to replace string values in the inputString.
  • Utilize replaceAll instead of replace to handle multiple occurrences of the same variable.

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))

Answer №5

To efficiently replace all occurrences and loop twice, you can utilize the replaceAll method.

function performReplace(variables, input) {
  let result = input;
  for (let i = 0; i < variables.length; i++) {
     result = result.replaceAll(variables[i].name, variables[i].value);
  }
  for (let i = 0; i < variables.length; i++) {
     result = result.replaceAll(variables[i].name, variables[i].value);
  }
  return result;
}

Answer №6

Utilizing the power of "reduce" in my solution

const variables = [
  { name: "%FIRST%", value: "John" },
  { name: "%LAST%", value: "Doe" },
  { name: "%AGE%", value: "30" }
];
const input =
  "Hello, my name is %FIRST% %LAST%, I am %AGE% years old";

function applyMagic(inputString, variableList) {
  const replaceVariable = (s, v) =>
    v.reduce((prev = "", { name, value }) => prev.replace(name, value), s);
  const updatedVariables = variableList.map((v) => ({
    ...v,
    value: replaceVariable(v.value, variableList)
  }));

  return replaceVariable(inputString, updatedVariables);
}

console.log(applyMagic(input, variables));

You can also opt to convert my code into a prototype like so:

const input =
  "Hello, my name is %FIRST% %LAST%, I am %AGE% years old";

String.prototype.applyMagic = function (variableList) {
  const replaceVariable = (s, v) =>
    v.reduce((prev = "", { name, value }) => prev.replace(name, value), s);
  const updatedVariables = variableList.map(({ value, ...rest }) => ({
    ...rest,
    value: replaceVariable(value, variableList)
  }));

  return replaceVariable(this, updatedVariables);
};


console.log(
  input.applyMagic([
    { name: "%FIRST%", value: "John" },
    { name: "%LAST%", value: "Doe" },
    { name: "%AGE%", value: "30" }
  ])
)

Answer №7

Quite detailed version, however if you aim to accomplish it in a single pass, loop through each character and once you encounter the second % (indicating end), proceed with replacing 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%`;

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))

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Transforming a JSON string containing multiple arrays into a JavaScript object

My JSON file is structured as follows: { "items":[ { "username":"abc", "orderID":"1234", "commentHistory":[ { "comment":"Comment Date: 2016/12/09 13:44:23" }, { ...

Would it be frowned upon in JavaScript to use "if (somestring in {'oneoption':false, 'secondoption':false})"?

Is the use of this construct considered a bad practice in JavaScript and could it lead to unexpected behavior? if (e.target.name in {name: '', number: ''}) { // do something } This code checks if the 'name' attribute of an ...

Utilizing an array of objects to import images

Within the data file, there exists an array of objects where icons are described as properties of these objects. The question arises: how can we utilize these icons as links? export const socialLinks = [ { url: "https://www.youtube.com", ...

There was a lack of dynamic content on the webpage when using the view/template engine (Handlebars)

I'm currently using the Handlebars template engine in my project. Despite not encountering any errors in the console, I'm facing an issue with displaying dynamic content in the index.hbs file that is rendered from app.js. app.js const express = ...

How does Sizzle JS function?

While investigating the sizzle.js source code for a project, I stumbled upon an interesting discovery. Towards the end of the code, there is a line that reads: window.Sizzle = Sizzle; However, there doesn't seem to be any declaration of a variable n ...

Improving Performance in JavaScript by Altering Class Properties

I need to dynamically change the color properties of two classes, but my current code is sluggish since these classes are repeated over 100 times throughout the code. Any tips on optimizing this for better performance? if (mainColor) { var elColors = ...

Retrieving the value of a basic object

When I receive an object from an API, the data looks like this- { "query1": 0.443} My goal is to extract the number 0.443 by using: request(options, function (error, response, body) { if (error) throw new Error(error); ...

Attempting to extract information from mySQL and convert it into a PHP array

Lately, I have dedicated my time to a project. In this project, I have set up a database which stores various elements like id, title, imgUrl, intro, and content. My goal is to fetch this data from the MySQL database and organize it into a PHP array as dep ...

Discover supplementary characters to incorporate into a JavaScript string

I am facing a challenge with identifying three added characters in the second string that are not present in the first string. These added characters could be located anywhere within the string. For example: string1 = "hello" string2 = "aaahello" // =&g ...

Converting a JSONArray to a String in Java

I am working with a JSONArray that has the following structure: How can I convert this array to a formatted string? If I attempt to use: json.toString(); The resulting string is as follows: ["package.package.ChecklistModels.ChecklistAnswer@405dddd8", ...

Encountering a discord bot malfunction while on my Ubuntu server

My discord bot runs smoothly on my Windows 10 setup, but when deployed to the server running Ubuntu Server 20, it encounters a specific error. The issue arises when trying to handle incoming chat messages from the server. While I can read and respond to m ...

The instance does not have a definition for the property or method "foo" that was referenced during rendering

[Vue warn]: Property or method "modelInfo" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. Whenever I ...

Passing a single item from a list as a prop in Vue.js

Imagine having the following set of information in data: data: { todos: [ { id: 1, title: "Learn Python" }, { id: 2, title: "Learn JS" }, { id: 3, title: "Create WebApp" } ] } Now, I aim to send only the item with an id of 2 t ...

What is the best way to switch content between tabs using ajax and php?

I have organized my content into two tabs and I am switching between the tabs using JavaScript. <div class='tab-container'> <div class='tab-1'> <?php $sql="SELECT * FROM posts WHERE status='tab1'"; echo "<d ...

How can I substitute a specific capture group instead of the entire match using a regular expression?

I'm struggling with the following code snippet: let x = "the *quick* brown fox"; let y = x.replace(/[^\\](\*)(.*)(\*)/g, "<strong>$2</strong>"); console.log(y); This piece of code replaces *quick* with <strong& ...

Is it possible to utilize a pre-existing JS "package" with Node.JS?

Recently, I decided to convert my existing JS code into an NPM package for easier distribution. The package is called "my-pkg" and includes the following files: my-pkg.js package.json my-pkg.js function ping() { console.log("Hi!"); } package.json ...

I am receiving a success message from webpack indicating that the compilation was successful, but I am encountering a blank page in the

My app.js looks like this: import Home from "./pages/home/Home"; import Login from "./pages/login/Login"; import Profile from "./pages/profile/Profile"; import Register from "./pages/register/Register"; import { Brow ...

Unique loading animations are assigned to each individual page within the Next.js framework

Is there a way to have unique loading animations for each of my website pages during the loading process? How can I achieve this? I've attempted to put the loading component on the page component directly, but it doesn't seem to work: //Page com ...

Changing synchronous functions to asynchronous

Attempting to transform synchronous calls into asynchronous ones using when...done. Despite being new at this, after extensive reading on the topic for the past two days, my code should work as intended. However, while it does function, it doesn't exe ...

Does mysql_fetch_array combine mysql_fetch_assoc and mysql_fetch_row functions?

Recently, I've been delving into the world of mysql_fetch_* methods. Here's a summary based on my research from the official PHP.org website. mysql_fetch_array — Retrieves a result row as an associative array, numeric array, or both mysql_fetc ...