Как я могу узнать, сколько совпадений заменяется в строке? - PullRequest
0 голосов
/ 16 октября 2018

Допустим, у меня есть функция, которая выглядит следующим образом:

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

Какой самый чистый и надежный способ узнать, сколько совпадений заменено в строке?

IМы думали о следующих возможных решениях:

  • Оберните значение replacement прокси-сервером, который регистрирует каждый раз, когда к его прокси-значению обращаются.Это не может быть перенесено на более старые версии JS.

  • Переопределить алгоритм, используемый в String.prototype.replace, чтобы каждый раз, когда он заменял что-то, он записывал это.Это не совсем чисто.

  • Если search является строкой или неглобальным регулярным выражением, я могу проверить, если string включает / соответствует ей.Но если search является глобальным регулярным выражением, когда JS будет иметь поддержку lookbehinds, я не уверен, что это сработает, может быть, все совпадения вычисляются до их фактической замены?Если это не так, любая замена может привести к тому, что приведенные ниже взгляды больше не будут совпадать или теперь будут соответствовать тем вещам, которые не соответствовали бы в исходной строке.

Что делатьВы думаете, это лучшее решение проблемы?

1 Ответ

0 голосов
/ 16 октября 2018

Для простых случаев, когда заменой является строка, для второго аргумента .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, '$1_' ));

Гораздо более ленивая, но более простая в реализации версия - просто вызвать match и проверить length результата, хотя для этого потребуется пройти строку срегулярное выражение дважды :

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, '$1_' ));

Если поиск является строкой или неглобальным регулярным выражением, я могу проверить, содержит ли строка / соответствует ли она.Но если поиск является глобальным регулярным выражением, когда JS будет иметь поддержку lookbehinds, я не уверен, что это сработает, может быть, все совпадения вычисляются до их фактической замены?Если это не так, любая замена может привести к тому, что приведенные ниже взгляды больше не будут совпадать или теперь будут совпадать с вещами, которые не соответствовали бы в исходной строке.

Это не будетпроблема - единственная проблема с использованием .match для получения счетчика в дополнение к .replace заключается в том, что для этого требуется дважды пройти строку.Все замещения строки рассчитываются сразу, где обходные пути смотрят на исходную строку .Затем, когда все совпадения найдены и замены рассчитаны, каждая подходящая подстрока заменяется своей заменой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...