我怎么知道字符串中有多少匹配项被替换了?

How can I know how many matches get replaced in a string?

假设我有一个如下所示的函数:

function countReplacements ( string, search, replacement ) {
    string.replace ( search, replacement );
}

了解字符串中有多少匹配项被替换的最干净、最可靠的方法是什么?

我想到了以下可能的解决方案:

您认为解决问题的最佳方法是什么?

对于替换为字符串的普通情况,对于 .replace 的第二个参数,使用回调函数而不是普通的 replacement 字符串,并让回调递增一个变量:

function countReplacements(string, search, replacement) {
  let count = 0;
  const result = string.replace(search, () => {
    count++;
    return replacement;
  });
  return { count, result };
}

console.log(countReplacements('foobar', /o/g, 'a'));

对于更复杂的情况,当 replacement 是一个函数或包含组引用的字符串时,您要么必须自己重新实现 String.prototype.replace:使用提供给 .replace 获取完整匹配和分组:

function countReplacements(string, search, replacement) {
  let count = 0;
  const result = string.replace(search, (match, ...groups) => {
    count++;
    return replacement
      .replace(/$(\d+|&)/g, (_, indicator) => {
        if (indicator === '&') return match;
        if (/^\d+$/.test(indicator)) return groups[indicator - 1];
        // and so on for other `$`s
      });
  });
  return { count, result };
}

console.log(countReplacements ( 'foobar', /(o)/g, '_' ));

一个更懒惰但更容易实现的版本就是调用 match 并检查结果的 length,尽管这需要使用正则表达式 [=49= 遍历字符串]两次:

function countReplacements(string, search, replacement) {
  const match = string.match(search);
  const count = match ? match.length : 0;
  const result = string.replace(search, replacement);
  return { count, result };
}

console.log(countReplacements ( 'foobar', /(o)/g, '_' ));

If search is a string or a non-global regex I can check if string includes/matches it. But if search is a global regex, when JS will have support for lookbehinds I'm not sure this will work, maybe all matches are computed before actually replacing them? If this isn't the case any replacement may cause the following lookbehinds to no longer match, or to now match things that it wouldn't have matched in the original string.

这不是问题 - 除了 .replace 之外,使用 .match 获取计数的唯一问题是它需要遍历字符串两次。字符串的替换全部一次计算,其中环视正在查看 原始字符串 。然后,一旦找到所有匹配项并计算出替换项,每个匹配的子字符串将被替换为它的替换项。