简体   繁体   English

使用占位符和替换对象格式化 JavaScript 字符串?

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

I have a string with say: My Name is %NAME% and my age is %AGE%.我有一个字符串说: My Name is %NAME% and my age is %AGE%.

%XXX% are placeholders. %XXX%是占位符。 We need to substitute values there from an object.我们需要用一个对象替换那里的值。

Object looks like: {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"}对象看起来像: {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"}

I need to parse the object and replace the string with corresponding values.我需要解析对象并将字符串替换为相应的值。 So that final output will be:所以最终输出将是:

My Name is Mike and my age is 26.我的名字是迈克,我的年龄是 26 岁。

The whole thing has to be done either using pure javascript or jquery.整个事情必须使用纯 javascript 或 jquery 来完成。

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.对于适合特定 OP 要求的答案,您可以使用String.prototype.replace()进行替换。

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 . js小提琴

If some of your replacements are not strings, be sure they exists in the object first.如果您的某些替换不是字符串,请确保它们首先存在于对象中。 If you have a format like the example, ie wrapped in percentage signs, you can use the in operator to achieve this.如果您有类似示例的格式,即包裹在百分号中,您可以使用in运算符来实现此目的。

jsFiddle . js小提琴

However, if your format doesn't have a special format, ie 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.但是,如果您的格式没有特殊格式,即任何字符串,并且您的替换对象没有null原型,请使用Object.prototype.hasOwnProperty() ,除非您可以保证您的潜在替换子字符串都不会与原型上的属性名称冲突。

jsFiddle . js小提琴

Otherwise, if your replacement string was 'hasOwnProperty' , you would get a resultant messed up string.否则,如果你的替换字符串是'hasOwnProperty' ,你会得到一个混乱的字符串。

jsFiddle . js小提琴


As a side note, you should be called replacements an Object , not an Array .作为旁注,您应该被称为replacements Object ,而不是Array

How about using ES6 template literals?使用 ES6 模板文字怎么样?

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.您可以使用 JQuery(jquery.validate.js) 使其轻松工作。

$.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归功于 jquery.validate.js 团队

Currently there is still no native solution in Javascript for this behavior.目前,Javascript 中仍然没有针对此行为的本机解决方案。 Tagged templates are something related, but don't solve it. 标记模板是相关的,但不要解决它。

Here there is a refactor of alex's solution with an object for replacements.这里有一个对alex 解决方案的重构,其中包含一个用于替换的对象。

The solution uses arrow functions and a similar syntax for the placeholders as the native Javascript interpolation in template literals ( {} instead of %% ).该解决方案使用箭头函数占位符的类似语法作为模板文字中的本机 Javascript 插值{}而不是%% )。 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更新 2020-12-10

Elegant reduced solution with groups, as suggested by @Kade in the comments :正如@Kade 在评论中所建议的那样,带有组的优雅简化解决方案:

 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更新 2021-01-21

Support empty string as a replacement, as suggested by @Jesper in the comments :正如@Jesper 在评论中所建议的那样,支持空字符串作为替换:

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

As with modern browser, placeholder is supported by new version of Chrome / Firefox, similar as the C style function printf() .与现代浏览器一样,新版本的 Chrome / Firefox 支持占位符,类似于 C 风格的函数printf()

Placeholders:占位符:

  • %s String. %s字符串。
  • %d , %i Integer number. %d , %i整数。
  • %f Floating point number. %f浮点数。
  • %o Object hyperlink. %o对象超链接。

eg例如

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.在 Chrome 中,使用快捷键Ctrl + Shift + JF12打开开发者工具。
  • In Firefox, use shortcut Ctrl + Shift + K or F12 to open developer tool.在 Firefox 中,使用快捷键Ctrl + Shift + KF12打开开发者工具。

@Update - nodejs support @Update - nodejs 支持

Seems nodejs don't support %f , instead, could use %d in nodejs.似乎 nodejs 不支持%f ,相反,可以在 nodejs 中使用%d With %d number will be printed as floating number, not just integer.使用%d数字将打印为浮点数,而不仅仅是整数。

Just use replace()只需使用replace()

var values = {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"};
var substitutedString = "My Name is %NAME% and my age is %AGE%.".replace("%NAME%", $values["%NAME%"]).replace("%AGE%", $values["%AGE%"]);

You can use a custom replace function like this:您可以像这样使用自定义替换功能:

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

function substitute(str, data) {
    var output = str.replace(/%[^%]+%/g, function(match) {
        if (match in data) {
            return(data[match]);
        } else {
            return("");
        }
    });
    return(output);
}

var output = substitute(str, replaceData);

You can see it work here: http://jsfiddle.net/jfriend00/DyCwk/ .你可以在这里看到它的工作原理:http: //jsfiddle.net/jfriend00/DyCwk/

If you want to do something closer to console.log like replacing %s placeholders like in如果你想做一些更接近 console.log 的事情,比如替换 %s 占位符,比如

>console.log("Hello %s how are you %s is everything %s?", "Loreto", "today", "allright")
>Hello Loreto how are you today is everything allright?

I wrote this我写了这个

 function log() { var args = Array.prototype.slice.call(arguments); var rep= args.slice(1, args.length); var i=0; var output = args[0].replace(/%s/g, function(match,idx) { var subst=rep.slice(i, ++i); return( subst ); }); return(output); } res=log("Hello %s how are you %s is everything %s?", "Loreto", "today", "allright"); document.getElementById("console").innerHTML=res;
 <span id="console"/>

you will get你会得到

>log("Hello %s how are you %s is everything %s?", "Loreto", "today", "allright")
>"Hello Loreto how are you today is everything allright?"

UPDATE更新

I have added a simple variant as String.prototype useful when dealing with string transformations, here is it:我添加了一个简单的变体作为String.prototype在处理字符串转换时很有用,这里是:

String.prototype.log = function() {
    var args = Array.prototype.slice.call(arguments);
    var rep= args.slice(0, args.length);
    var i=0;
    var output = this.replace(/%s|%d|%f|%@/g, function(match,idx) {
      var subst=rep.slice(i, ++i);
      return( subst );
    });
    return output;
   }

In that case you will do在这种情况下,你会做

"Hello %s how are you %s is everything %s?".log("Loreto", "today", "allright")
"Hello Loreto how are you today is everything allright?"

Try this version here在这里试试这个版本

This allows you to do exactly that这使您可以做到这一点

NPM: https://www.npmjs.com/package/stringinject NPM: https ://www.npmjs.com/package/stringinject

GitHub: https://github.com/tjcafferkey/stringinject GitHub: https ://github.com/tjcafferkey/stringinject

By doing the following:通过执行以下操作:

var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });

// My username is tjcafferkey on Git

I have written a code that lets you format string easily.我编写了一个代码,可以让您轻松地格式化字符串。

Use this function.使用此功能。

function format() {
    if (arguments.length === 0) {
        throw "No arguments";
    }
    const string = arguments[0];
    const lst = string.split("{}");
    if (lst.length !== arguments.length) {
        throw "Placeholder format mismatched";
    }
    let string2 = "";
    let off = 1;
    for (let i = 0; i < lst.length; i++) {
        if (off < arguments.length) {
            string2 += lst[i] + arguments[off++]
        } else {
            string2 += lst[i]
        }
    }
    return string2;
}

Example例子

format('My Name is {} and my age is {}', 'Mike', 26);

Output输出

My Name is Mike and my age is 26我的名字是迈克,我的年龄是 26

As a quick example:举个简单的例子:

var name = 'jack';
var age = 40;
console.log('%s is %d yrs old',name,age);

The output is:输出是:

jack is 40 yrs old杰克 40 岁

Here is another way of doing this by using es6 template literals dynamically at runtime.这是在运行时动态使用 es6 模板文字的另一种方法。

 const str = 'My name is ${name} and my age is ${age}.' const obj = {name:'Simon', age:'33'} const result = new Function('const {' + Object.keys(obj).join(',') + '} = this.obj;return `' + str + '`').call({obj}) document.body.innerHTML = result

const stringInject = (str = '', obj = {}) => {
  let newStr = str;
  Object.keys(obj).forEach((key) => {
    let placeHolder = `#${key}#`;
    if(newStr.includes(placeHolder)) {
      newStr = newStr.replace(placeHolder, obj[key] || " ");
    }
  });
  return newStr;
}
Input: stringInject("Hi #name#, How are you?", {name: "Ram"});
Output: "Hi Ram, How are you?"

ES6: ES6:

const strFormat = (str, ...args) => args.reduce((s, v) => s.replace('%s', v), str);

// Use it like:
const result = strFormat('%s is %s yrs old', 'name', 23);

This is a merged solution of Gerson Diniz and Shubham Vyas.这是 Gerson Diniz 和 Shubham Vyas 的合并解决方案。

It is possible to pass a set of arguments or an object.可以传递一组参数或一个对象。

 function strSwap(str) { if (!str) return null; let args = []; for (let a of arguments) args.push(a); args.shift(); if (!args.length) return null; // replacement by object - {{prop}} if (!!(args[0].constructor && args[0].constructor.name.toLowerCase() === 'object')) { for (let i in args[0]) { let n = `{{${i}}}`; str = str.includes(n) ? str.replaceAll(n, args[0][i] + '') : str; } } // replacement by placeholders - %s else { str = args.reduce((s, v) => s.replace('%s', v), str); } return str; } // --------------------- console.log(strSwap('Hello %s, my name is %s.', 'alice', 'bob')); console.log(strSwap('Hello {{a}}, my name is {{b}}. Hello {{b}}.', { a: 'alice', b: 'bob' }));

Lots of good/similar answers here.这里有很多好的/类似的答案。 I wanted the ability to easily get a nested key in an object (or perhaps some JSON data structure) for substitution, so I took the following simple approach:我希望能够轻松地在对象(或者可能是一些 JSON 数据结构)中获取嵌套键以进行替换,因此我采用了以下简单方法:

const getKey = (d, path) => {
  // path can be a string like 'key1.key2' or an iterable of keys
  if (typeof(path) === 'string') {
    path = path.split('.')
  }
  return path.reduce((x, y) => x[y], d)
}

const inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> getKey(obj, g));


// Example

> const str = 'there are ${a} ways to ${b.c}'
undefined
> inject(str, {'a':'many', 'b': {'c': 'skin a cat'}})
'there are many ways to skin a cat'

Some inspiration from this and this .一些灵感来自thisthis

Another solution if you're using node.js is StackExchange's own formatUnicorn utility function ( https://www.npmjs.com/package/format-unicorn ):如果您使用的是 node.js,另一个解决方案是 StackExchange 自己的formatUnicorn实用程序函数( https://www.npmjs.com/package/format-unicorn ):

let x = {name:'jason', food:'pine cones'};
let s = '{name} enjoys a delicious bowl of {food}';

let formatted = x.formatUnicorn(s);

Also, a bit of an edge case, but if you aren't using Node but you do just happen to be writing a userscript for SE sites, then formatUnicorn will already be on the String prototype.此外,还有一些极端情况,但如果您没有使用 Node,但恰好正在为 SE 站点编写用户脚本,那么formatUnicorn将已经在 String 原型上。

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

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