javascript - 即使有匹配项,while 循环中的 Regex exec 也会返回 null

标签 javascript regex while-loop do-while

根据我的研究,正则表达式 replace 不是异步的。所以我有点困惑为什么在 do-while 循环中匹配和替换有时会匹配失败。

我在下面创建了一个片段,可以选择“双重检查”该值是否包含任何匹配项,但我不知道为什么双重检查实际上会阻止它忽略匹配项。

您将在控制台中看到,当 injectableRegex.exec()do-while 循环中运行两次时,它会正确替换所有匹配项。

更新:即使这种方法也不一致,因为我发现有时 doubleCheck 部分正确匹配,然后随后的 exec 调用失败

const getInjectedPhrase = (phrase, injections, doubleCheck) => {
  let value = phrase;
  // only need to attempt to replace the injectables in the phrase is we've been passed injections
  if (injections && phrase.length > 1) {
    const injectableRegex = /{{\s?([\w-]+)\s?}}/g; // find any matching injectable, and extract its key
    let match;
    window.console.log('initial phrase:', phrase);
    // check if dictionary value contains injectable sections ie. sections surrounded by {{ }}
    do {
      // WHY IS THIS A THING!?
      if (doubleCheck) {
        injectableRegex.exec(value)
      }
      match = injectableRegex.exec(value);
      if (match) {
        /*
        match[0] -> {{ x }}
        match[1] -> x
        */
        const injectionValue = injections[match[1]];

        const injectionValueType = typeof injectionValue;
        if (
          injectionValueType === "string" ||
          injectionValueType === "number"
        ) {
          // globally replace the value with the injection's value
          value = value.replace(new RegExp(match[0], "g"), `${injectionValue}`);
          window.console.log('partial replace phrase:', value);
        }
      }
    } while (match !== null);
  }
  window.console.log('returned phrase:', value);
  return value;
};

window.console.log('WITHOUT DOUBLE CHECKING');
getInjectedPhrase(
  "foo {{partialCount}} of {{count}} bars", {
    partialCount: 3,
    count: 4
  },
  false
);
window.console.log('USING DOUBLE CHECKING');
getInjectedPhrase(
  "foo {{partialCount}} of {{count}} bars", {
    partialCount: 3,
    count: 4
  },
  true
);

最佳答案

问题是正则表达式保留了一个 lastIndex 属性,它跟踪最后一个匹配项的结束索引。在

foo {{partialCount}} of {{count}} bars

匹配

{{partialCount}}

导致 lastIndex 属性随后被设置为 20 - 第二个 之后的位置。

然后,当您重新分配字符串到

foo 3 of {{count}} bars

使用相同的正则表达式尝试匹配将从该字符串的索引 20 开始,过去 {{count}}部分,所以匹配失败。

一种选择是每次手动将 lastIndex 重置为 0:

const getInjectedPhrase = (phrase, injections, doubleCheck) => {
  let value = phrase;
  // only need to attempt to replace the injectables in the phrase is we've been passed injections
  if (injections && phrase.length > 1) {
    const injectableRegex = /{{\s?([\w-]+)\s?}}/g; // find any matching injectable, and extract its key
    let match;
    window.console.log('initial phrase:', phrase);
    // check if dictionary value contains injectable sections ie. sections surrounded by {{ }}
    do {
      injectableRegex.lastIndex = 0;
      match = injectableRegex.exec(value);
      if (match) {
        /*
        match[0] -> {{ x }}
        match[1] -> x
        */
        const injectionValue = injections[match[1]];

        const injectionValueType = typeof injectionValue;
        if (
          injectionValueType === "string" ||
          injectionValueType === "number"
        ) {
          // globally replace the value with the injection's value
          value = value.replace(new RegExp(match[0], "g"), `${injectionValue}`);
          window.console.log('partial replace phrase:', value);
        }
      }
    } while (match !== null);
  }
  window.console.log('returned phrase:', value);
  return value;
};

window.console.log('WITHOUT DOUBLE CHECKING');
getInjectedPhrase(
  "foo {{partialCount}} of {{count}} bars", {
    partialCount: 3,
    count: 4
  },
  false
);

更好的选择是替换一次全部,使用回调函数,无需手动迭代、替换和重置正则表达式对象:

const getInjectedPhrase = (str, obj) => str.replace(
  /{{\s?([\w-]+)\s?}}/g,
  (_, key) => obj[key]
);

console.log(
  getInjectedPhrase(
    "foo {{partialCount}} of {{count}} bars", {
      partialCount: 3,
      count: 4
    },
  )
);

关于javascript - 即使有匹配项,while 循环中的 Regex exec 也会返回 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53753754/

相关文章:

javascript - 使用 BIOSTALL google map library 在 Code igniter 中设置 Google map pans

javascript - 奇怪的返回没有标志的 javascript 正则表达式 'g'

正则表达式一个参数数目未知的字符串

MySQL RegExp 出现错误 'repetition-operator operand invalid'

c - 为什么这个函数返回字符串的正确长度? (增加一个字符指针)

javascript - 在 while 循环 D3 中更新参数

javascript 使用 cookie 将变量传递到另一个页面

javascript - 强制 $.each() 循环等待动画完成后再继续

javascript - 将源更改为 <audio> html5 元素

bash 命令在 while 循环中重定向标准输入(使用 sed)