Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Format a JavaScript string using placeholders and an object of substitutions?

People also ask

How do you replace a placeholder in a string?

You can easily use it to replace placeholders by name with this single method call: StringUtils. replaceEach("There's an incorrect value '%(value)' in column # %(column)", new String[] { "%(value)", "%(column)" }, new String[] { x, y });

What is ${} in JavaScript?

${} is a placeholder that is used in template literals. You can use any valid JavaScript expression such as variable, arithmetic operation, function call, and others inside ${}. The expression used inside ${} is executed at runtime, and its output is passed as a string to template literals.


The requirements of the original question clearly couldn't benefit from string interpolation, as it seems like it's a runtime processing of arbitrary replacement keys.

However, if you just had to do string interpolation, you can use:

const str = `My name is ${replacements.name} and my age is ${replacements.age}.`

Note the backticks delimiting the string, they are required.


For an answer suiting the particular OP's requirement, you could use String.prototype.replace() for the replacements.

The following code will handle all matches and not touch ones without a replacement (so long as your replacement values are all strings, if not, see below).

var replacements = {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"},
    str = 'My Name is %NAME% and my age is %AGE%.';

str = str.replace(/%\w+%/g, function(all) {
   return replacements[all] || all;
});

jsFiddle.

If some of your replacements are not strings, be sure they exists in the object first. If you have a format like the example, i.e. wrapped in percentage signs, you can use the in operator to achieve this.

jsFiddle.

However, if your format doesn't have a special format, i.e. any string, and your replacements object doesn't have a null prototype, use Object.prototype.hasOwnProperty(), unless you can guarantee that none of your potential replaced substrings will clash with property names on the prototype.

jsFiddle.

Otherwise, if your replacement string was 'hasOwnProperty', you would get a resultant messed up string.

jsFiddle.


As a side note, you should be called replacements an Object, not an Array.


How about using ES6 template literals?

var a = "cat";
var b = "fat";
console.log(`my ${a} is ${b}`); //notice back-ticked string

More about template literals...


You can use JQuery(jquery.validate.js) to make it work easily.

$.validator.format("My name is {0}, I'm {1} years old",["Bob","23"]);

Or if you want to use just that feature you can define that function and just use it like

function format(source, params) {
    $.each(params,function (i, n) {
        source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
    })
    return source;
}
alert(format("{0} is a {1}", ["Michael", "Guy"]));

credit to jquery.validate.js team


As with modern browser, placeholder is supported by new version of Chrome / Firefox, similar as the C style function printf().

Placeholders:

  • %s String.
  • %d,%i Integer number.
  • %f Floating point number.
  • %o Object hyperlink.

e.g.

console.log("generation 0:\t%f, %f, %f", a1a1, a1a2, a2a2);

BTW, to see the output:

  • In Chrome, use shortcut Ctrl + Shift + J or F12 to open developer tool.
  • In Firefox, use shortcut Ctrl + Shift + K or F12 to open developer tool.

@Update - nodejs support

Seems nodejs don't support %f, instead, could use %d in nodejs. With %d number will be printed as floating number, not just integer.


Currently there is still no native solution in Javascript for this behavior. Tagged templates are something related, but don't solve it.

Here there is a refactor of alex's solution with an object for replacements.

The solution uses arrow functions and a similar syntax for the placeholders as the native Javascript interpolation in template literals ({} instead of %%). Also there is no need to include delimiters (%) in the names of the replacements.

There are two flavors (three with the update): descriptive, reduced, elegant reduced with groups.

Descriptive solution:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '26',
};

const string = stringWithPlaceholders.replace(
  /{\w+}/g,
  placeholderWithDelimiters => {
    const placeholderWithoutDelimiters = placeholderWithDelimiters.substring(
      1,
      placeholderWithDelimiters.length - 1,
    );
    const stringReplacement = replacements[placeholderWithoutDelimiters] || placeholderWithDelimiters;
    return stringReplacement;
  },
);

console.log(string);

Reduced solution:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '26',
};

const string = stringWithPlaceholders.replace(/{\w+}/g, placeholder =>
  replacements[placeholder.substring(1, placeholder.length - 1)] || placeholder
);

console.log(string);

UPDATE 2020-12-10

Elegant reduced solution with groups, as suggested by @Kade in the comments:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '26',
};

const string = stringWithPlaceholders.replace(
  /{(\w+)}/g, 
  (placeholderWithDelimiters, placeholderWithoutDelimiters) =>
    replacements[placeholderWithoutDelimiters] || placeholderWithDelimiters
);

console.log(string);

UPDATE 2021-01-21

Support empty string as a replacement, as suggested by @Jesper in the comments:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '',
};

const string = stringWithPlaceholders.replace(
  /{(\w+)}/g, 
  (placeholderWithDelimiters, placeholderWithoutDelimiters) =>
  replacements.hasOwnProperty(placeholderWithoutDelimiters) ? 
    replacements[placeholderWithoutDelimiters] : placeholderWithDelimiters
);

console.log(string);