Подсчет количества подстроки в строке на JavaScript

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

JS
Скопировать код
const countOccurrences = (text, search) => (text.match(new RegExp(search, 'g')) || []).length;
console.log(countOccurrences('яблоко банан яблоко', 'яблоко'));  // Результат: 2

Для определения количества вхождений подстроки search в строку text используйте функцию countOccurrences. Взаимодействие объекта RegExp с глобальным флагом 'g' обеспечивает глобальный поиск. Если совпадений не обнаружено, возвращается 0 благодаря оператору ||, иначе — количество элементов массива, созданного с помощью .match().

Кинга Идем в IT: пошаговый план для смены профессии

Анализ метода match и флагов регулярных выражений

Метод .match() в JavaScript, использующийся совместно с регулярными выражениями, служит мощым инструментом для поиска шаблонов в тексте. Поскольку по умолчанию данный поиск чутко реагирует на разницу в регистрах, он может обеспечивать точный подсчёт в ситуациях, где это критически важно.

Тем не менее, помните, что .match() в случае отсутствия совпадений возвращает null. Чтобы избежать ошибки при попытке определить длину null, применяется логический оператор ||, гарантирующий возврат 0 в случае неудачи поиска.

JS
Скопировать код
const caseSensitiveCount = (text, search) => {
  // Нашли совпадение! Или не нашли...
  const matches = text.match(new RegExp(search, 'g'));
  return matches ? matches.length : 0;
};

Альтернатива: подсчет с применением split

Метод .split() может стать альтернативой .match(). Этот метод декомпозирует строку на массив, делая это каждый раз при вхождении подстроки. Вычитая единицу из длины полученного массива, мы получаем кол-во вхождений.

JS
Скопировать код
const countWithSplit = (text, search) => {
  // Делим и властвуем! Кроме случаев, когда разделитель — пустая строка...
  if (!search.length) return text.length ? text.length – 1 : 0;
  return text.split(search).length – 1;
};

Однако имейте в виду, что при пустой строке search поведение .split() становится непредсказуемо: вместо того, чтобы делить по каждому символу, он возвращает массив с исходной строкой, что может привести к неверному результату из-за ошибки на единицу.

Учет перекрывающихся подстрок

С регулярными выражениями часто возникает проблема пропуска перекрывающихся подстрок — они не учтены при стандартном поиске. Но можно избежать этого ограничения, выполнив ручной обход текста.

JS
Скопировать код
const countOverlapping = (text, search) => {
  // В предвкушении моих итераций, они наблюдают...
  // Избежать бесконечных циклов поможет переход через текст на должное расстояние
  let count = 0, position = 0, step = search.length > 0 ? search.length : 1;
  while ((position = text.indexOf(search, position)) !== -1) {
    count++;
    position += step; 
  }
  return count;
};

Эта функция успешно справляется с подсчётом даже пустых строк, избегает бесконечных циклов и гарантирует точность подсчёта.

Следите за производительностью

Кэширование длины строки search способно заметно повысить производительность. Это особо актуально, когда работа происходит с большими объёмами текста: запоминая это значение, можно избежать вычисления на каждой итерации.

Тесты производительности показали, что некоторые методы опережают поиск основанный на регулярных выражениях:

  1. Использование .indexOf() в связке с циклами для простых шаблонов значительно эффективнее.
  2. Кэширование размеров text и search ускоряет методы, не зависимые от этих параметров.
  3. Где это возможно, рекомендуется применять метод split(), так как его повсеместное использование на длинных строках может снизить производительность.

Визуализация

Попробуйте визуализировать это с помощью предметов из реального мира. Пусть вас просят подсчитать вхождения слова:

Markdown
Скопировать код
Исходная строка: "🍎🍌🍎🍎🍌🍎"
Подстрока для подсчета: "🍎"

Мы представляем себе ситуацию, когда считаем количество яблок "🍎" в корзине, полной фруктов. Каждый символ "🍎" обозначает искомый элемент.

Полезные материалы

  1. String.prototype.match() – JavaScript | MDN – Инструкция по использованию .match() на MDN.
  2. JavaScript: How many times a character occurs in a string? – Stack Overflow – Ответы пользователям с практическими примерами на Stack Overflow.
  3. JavaScript RegExp Object – Работа с регулярными выражениями в JavaScript – Полное руководство по регулярным выражениям в JavaScript.
  4. JavaScript String search() Method – Обучающий материал W3Schools об использовании метода .search().
  5. Строки – Ответы на вопросы о работе со строками в JavaScript на портале JavaScript.info.
  6. ECMAScript 2015 Language Specification – ECMA-262 6th Edition – Официальная спецификация языка ECMAScript, содержащая детали о методах работы со строками в JavaScript.