我有一个具有无数属性的对象,例如颜色和品牌,它描述了一个产品。我正在寻找一种以段落形式动态生成产品描述的方法(因为API没有提供),我想出了一种方法,通过编写带有“props”的括号{{}}
包围的“模板”。我编写了一个函数来解析模板,方法是在字符串中注入对象属性,方法是将“props”替换为键的值。
例如:
对象:{color: 'white'}
模板:"The bowl is {{color}}."
结果:"The bowl is white."
出于某种原因,我的解析功能不起作用。 {{general_description}}
未被解析。
var obj = {
brand: "Oneida",
general_description: "Plate",
material: "China",
color: "Bone White",
product_width: "5\""
};
const templatePropRe = /{{(\w*)}}/g;
const parse = (template) => {
while ((result = templatePropRe.exec(template)) !== null) {
let match = result[0],
key = result[1];
template = template.replace(match, obj[key]);
}
return template;
}
console.log(parse('This {{color}}, {{material}} {{general_description}} supplied by {{brand}} has a width of {{product_width}}.'));
我按照示例>查找连续匹配中的MDN docs中提供的示例进行操作。它说我需要首先将正则表达式存储在变量(例如,templatePropRe
)中,因为表达式不能处于while循环条件中,否则它将无限循环。但是,如果我这样做,我的问题就解决了。看here ......什么都没破。
我使用String.prototype.match重写了该函数,它按预期工作,但我无法访问捕获所以我需要首先使用stripBrackets
剥离括号。请参阅使用match
here的工作示例。
我想知道的是为什么我的使用parse()
的RegExp.prototype.exec
功能不能正常工作?
从你的正则表达式中删除/g
标志。根据documentation,当这个标志出现时,它会更新正则表达式对象的lastIndex
属性,该属性指示下一次调用exec()
将开始搜索匹配的位置。
var obj = {
brand: "Oneida",
general_description: "Plate",
material: "China",
color: "Bone White",
product_width: "5\""
};
const templatePropRe = /{{(\w*)}}/;
const parse = (template) => {
while ((result = templatePropRe.exec(template)) !== null) {
let match = result[0],
key = result[1];
template = template.replace(match, obj[key]);
}
return template;
}
console.log(parse('This {{color}}, {{material}} {{general_description}} supplied by {{brand}} has a width of {{product_width}}.'));
发生这种情况是因为您修改并检查代码中的相同字符串。而regExp在每次执行后都会保存匹配子字符串的索引,您可以更改字符串的长度,而下一次执行的regEx将从您预期的其他点开始。
var obj = {
brand: "Oneida",
general_description: "Plate",
material: "China",
color: "Bone White",
product_width: "5\""
};
const templatePropRe = /{{(\w*)}}/g;
const parse = (template) => {
var resultStr = template;
while ((result = templatePropRe.exec(template)) !== null) {
let match = result[0],
key = result[1];
resultStr = resultStr.replace(match, obj[key]);
}
return resultStr;
}
console.log(parse('This {{color}}, {{material}} {{general_description}} supplied by {{brand}} has a width of {{product_width}}.'));
而不是执行两步替换(找到一个匹配,然后用所需的值替换第一个匹配)(这很容易出现像新的字符串传递给具有旧的已经无效的同一个RegExp时遇到的问题,索引),你可以使用callback method as a replacement argument inside a String#replace
method。这样,结果字符串将在每次匹配时动态构建,使代码执行得更快。
请参阅下面的示例修复:
var obj = {
brand: "Oneida",
general_description: "Plate",
material: "China",
color: "Bone White",
product_width: "5\""
};
const parse = (template) => {
return template.replace(/{{(\w*)}}/g, ($0, $1) => obj[$1] ? obj[$1] : $0 );
// ES5 way:
// return template.replace(/{{(\w*)}}/g, function($0, $1) {
// return obj[$1] ? obj[$1] : $0;
// });
}
console.log(parse('{{keep}} This {{color}}, {{material}} {{general_description}} supplied by {{brand}} has a width of {{product_width}}.'));
注意,在找到匹配之后,($0, $1) => obj[$1] ? obj[$1] : $0
代码执行以下操作:将整个匹配分配给$0
变量,将组1值分配给$1
;然后,如果在$1
中有一个名为obj
的键,则该值将被放入生成的字符串中的正确位置而不是匹配。否则,整个比赛被放回(如果你想删除一个不存在的密钥名称的''
,则用{{...}}
替换)。