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


92

我有一个字符串说: My Name is %NAME% and my age is %AGE%.

%XXX%是占位符。我们需要从对象那里替换值。

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

我需要解析对象并将字符串替换为相应的值。这样最终输出将是:

我的名字叫迈克,我的年龄是26。

整个过程必须使用纯JavaScript或jquery完成。


2
那看起来更像是一个对象而不是一个数组
Joel Coehoorn

3
你试过什么了?您是否看过字符串.replace()方法?(此外,您那里没有数组,您有一个对象。)
nnnnnn

1
那太丑了。您肯定会得到很好的服务{NAME: "Mike", AGE: 26, EVENT: 20}吗?当然,您仍然需要这些键在输入字符串中以百分号结尾。
davidchambers,

Answers:


150

显然,原始问题的要求无法从字符串插值中受益,因为这似乎是对任意替换键的运行时处理。

但是,如果只需要进行字符串插值,则可以使用:

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

请注意,反引号分隔字符串,这是必需的。


对于适合特定OP要求的答案,您可以使用它String.prototype.replace()来替代。

以下代码将处理所有匹配项,并且不进行任何替换就不会碰(只要替换值都是字符串,如果不是,请参见下文)。

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

如果某些替换项不是字符串,请确保它们首先存在于对象中。如果您具有类似示例的格式,即用百分号包裹,则可以使用in运算符来实现。

jsFiddle

但是,如果您的格式没有特殊格式(即任何字符串),并且您的替换对象没有null原型,请使用Object.prototype.hasOwnProperty(),除非您可以保证所有可能的替换子字符串都不会与原型上的属性名称发生冲突。

jsFiddle

否则,如果您的替换字符串为'hasOwnProperty',则您将得到结果混乱的字符串。

jsFiddle


附带说明一下,您应该称呼replacementsObject,而不是Array


2
+1。真好 虽然您可能想说return replacements[all] || all掩盖%NotInReplacementsList%案例。
nnnnnn

6
如果替换值是假的,这将不起作用。因此,最好使用以下return语句:return all in params ? params[all] : all;
MichaelHärtl2015年

@MichaelHärtl您的替代品不应该全部是字符串吗?如果要替换为空字符串,最好使用其他方法进行检查。
Alex 2015年

1
@alex我的情况是替换也可以是整数,甚至是0。在这种情况下,它不起作用。
MichaelHärtl2015年

@MichaelHärtl已更新为涵盖该案例。
Alex


13

您可以使用JQuery(jquery.validate.js)使其轻松工作。

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

或者,如果您只想使用该功能,则可以定义该功能并像

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

归功于jquery.validate.js团队


1
您绝对不希望仅为此加载该插件,但是我已经在使用它来验证页面上的表单...因此感谢您的提示!
nabrown 2015年

1
为每个数字创建一个正则表达式效率很低,最好匹配所有数字,然后替换是否在数组中找到该值呢?
亚历克斯


1
+非常好...而且$.each您可以String.prototype.format=function(p){var s=this,r=function(v,i){s=s.replace(new RegExp("\\{"+i+"\\}","g"),v);};p.forEach(r);return s;}这样做,因此您不必只为那个添加jquery;)
Larphoid

11

与现代浏览器一样,Chrome / Firefox的新版本也支持占位符,类似于C样式功能printf()

占位符:

  • %s 串。
  • %d%i整数。
  • %f 浮点数。
  • %o 对象超链接。

例如

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

顺便说一句,看输出:

  • 在Chrome中,使用快捷方式Ctrl + Shift + JF12打开开发人员工具。
  • 在Firefox中,使用快捷方式Ctrl + Shift + KF12打开开发人员工具。

@Update-Node.js支持

似乎nodejs不支持%f,而是可以%d在nodejs中使用。带%d数字将被打印为浮点数,而不仅仅是整数。



5

您可以使用以下自定义替换功能:

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

您可以在这里看到它的工作:http : //jsfiddle.net/jfriend00/DyCwk/


1
太酷了,Alex做了几乎完全相同的事情,但是用更少的代码行了(尽管三元运算符可能比if..else慢)。
RobG 2011年

嘿,我给了你+1!你们都做了替换功能,虽然功能不完全相同,但是非常相似。您的RegExp也有所不同,使用%%或$$或类似的定界符会更好一些,OP通常会在字符串中出现单个%或%,但不可能出现双精度。
RobG

4

如果您想做更接近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?

我写了这个

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"/>

你会得到

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

更新

我添加了一个简单的变量,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;
   }

在这种情况下,您将

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

在这里尝试这个版本


2
我在没有原型的情况下对您的函数进行了更改,formatMessage(message: string, values: string[]) { let i = 0; return message.replace(/%\w+%/g, (match, idx) => { return values[i++]; }); } 这将消息格式化为替换值的格式和数组,并寻找%SOME_VALUE%
baku

3

当前,此行为在Javascript中仍然没有本地解决方案。标记模板是相关的,但是不能解决。

这是alex解决方案的重构其中有一个替换对象。

该解决方案使用箭头函数占位符类似的语法作为模板文字{}而不是%%)中的本机Javascript插值。另外,在替换名称中也不需要包含定界符%)。

有两种口味:描述性和简化性。

描述性解决方案:

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

简化的解决方案:

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


1
为此,非常高兴能为占位符字符串和一个对象合并成这样的通用解决方案
Carlos P

@CarlosP,就是这个想法,拥有一个通用的解决方案。但是我认为这应该是语言的本机,因为这是一种常见的用例。
AMS777

2

这使您可以做到这一点

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

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

通过执行以下操作:

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

// My username is tjcafferkey on Git

2
但是,既然您可以在es6中做到这一点,那可能有点矫kill过正?
IonicBurger

1
这使您可以将字符串以一种格式存储在一个位置,然后在以后仅使用一个功能替换相应的项目。据我所知,这与es6模板文字无关。这种用法例如是翻译字符串,您将在其他地方使用该字符串并将其注入所需的值。
约翰·佩尔森

2

这是通过在运行时动态使用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


1

作为一个简单的例子:

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

输出为:

杰克40岁


7
很好,除非您除了将其记录到控制台外还想做其他事情。
Alex

13
那不是console.log吗?
drzaus

0
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?"

0

我编写了一个代码,可让您轻松设置字符串格式。

使用此功能。

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

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

输出量

我叫迈克,我26岁

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.