JavaScript:查找与 .exec() 的连续匹配

JavaScript: Finding successive matches with .exec()

我有一个具有无数属性的对象,例如描述产品的颜色和品牌。我正在寻找一种以段落形式动态生成产品描述的方法(因为 API 没有提供),我想出了一种方法,方法是编写 "templates" 具有 "props" 括在方括号 {{}} 中。我通过将 "props" 替换为键的值来在字符串中注入对象属性,从而为 "parse" 模板编写了一个函数。

例如:

对象:{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 under Examples > Finding successive matches. It says that I need to first store the regular expression in a variable (e.g., templatePropRe), for the expression cannot be in the while loop condition or it will loop indefinitely. However, if I do that, my problem is resolved. See here 中提供的示例...没有损坏。

我使用 String.prototype.match, and it works as expected, but I don't have access to the capture so I need to first strip off the brackets using stripBrackets. See the working example using 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, ([=10=], ) => obj[] ? obj[] : [=10=] );
  // ES5 way:
  // return template.replace(/{{(\w*)}}/g, function([=10=], ) {
  //       return obj[] ? obj[] : [=10=];
  // });
}

console.log(parse('{{keep}} This {{color}}, {{material}} {{general_description}} supplied by {{brand}} has a width of {{product_width}}.'));

请注意,此处找到匹配项后,([=12=], ) => obj[] ? obj[] : [=12=] 代码执行以下操作:整个匹配项分配给 [=13=] 变量,第 1 组值分配给 </code> ;然后,如果 <code>obj 中有一个名称为 </code> 的键,则该值将代替匹配项放入结果字符串中的正确位置。否则,整个匹配项将被放回原处(如果要删除键名不存在的 <code>{{...}},请替换为 '')。