Самый быстрый способ проверить строку, содержащую другую подстроку в JavaScript?

163

Я работаю с проблемой производительности на JavaScript. Поэтому я просто хочу спросить: какой самый быстрый способ проверить, содержит ли строка другую подстроку (мне просто нужно логическое значение)? Не могли бы вы предложить свою идею и пример кода фрагмента?

Син Хонг Чау
источник
Вы спрашиваете о фиксированной подстроке, или вам нужно регулярное выражение (меня немного смущает использование regexтега)?
Тим Пицкер
1
Этот пост был бы полезен .. stackoverflow.com/questions/1789945/javascript-string-contains
MTK
Как насчет разделения строки на массив вокруг пробела и пересечения массива? stackoverflow.com/questions/1885557/…
giorgio79
jsben.ch/#/aWxtF
EscapeNetscape

Ответы:

315

У вас есть две возможности:

  1. Регулярное выражение :

    (new RegExp('word')).test(str)
    // or
    /word/.test(str)
  2. indexOf:

    str.indexOf('word') !== -1

Регулярные выражения кажутся быстрее (по крайней мере, в Chrome 10).

Тест производительности - длинный стог сена
Тест производительности - длинный стог сена


Обновление 2011:

Нельзя с уверенностью сказать, какой метод быстрее. Различия между браузерами огромны. Хотя в Chrome 10 indexOfкажется быстрее, в Safari 5 indexOfявно медленнее, чем любой другой метод.

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


Обновление 2018:

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

Chrome: indexOf (~ 98% быстрее) <-- wow
Firefox: кэшированный RegExp (~ 18% быстрее)
IE11: кэшированный RegExp (~ 10% быстрее)
Edge: indexOf (~ 18% быстрее)
Safari: кэшированный RegExp (~ 0,4% быстрее)

Обратите внимание, что кэшированный RegExp это: var r = new RegExp('simple'); var c = r.test(str);в отличие от:/simple/.test(str)

Феликс Клинг
источник
3
Это может быть немного быстрее, только если текст для поиска известен заранее (т. Е. Не хранится в переменной), поскольку регулярное выражение создается механизмом JavaScript во время анализа. Если вы хотите найти строку, содержащуюся в переменной внутри другой строковой переменной, indexOf является самым быстрым, потому что вам нужно создать объект RegExp и обработать строку для экранирования специальных символов и т. Д.
Стивен Чунг
Исходя из опыта, indexOf может быть быстрее для поиска без учета регистра, если вы используете .toLowerCase для всего, что вы ищете,
Hayk Saakian
Я пишу приложение Office 2013, используя Microsoft Office Javascript API, и использование indexOfне работает. Я не уверен почему. Использование Regex, хотя и делает. Это крайний случай, но другие могут столкнуться с той же проблемой.
Энди Мерсер
По какой причине substr () не является одним из возможных решений? Я предполагаю, что это намного быстрее, чем решение RegEx во многих ситуациях. Я не знаю, как он сравнивается с indexOf (), хотя (так что если вы пропустили его, потому что он всегда работает хуже, чем indexOf (), тогда это нормально, возможно, добавьте примечание к этому эффекту.) РЕДАКТИРОВАТЬ: эта ссылка JSperf показывает некоторые интересные полученные результаты. Короткая версия: indexOf () - самый быстрый из всех методов, но он может варьироваться в зависимости от длины строки и любых повторяющихся шаблонов.
Бисон
1
@Bison: вы можете использовать substr, только если вы уже знаете, где искать. Я сосредоточился только на общих решениях.
Феликс Клинг
17

Это работает для вас?

string1.indexOf(string2) >= 0

Редактировать: Это не может быть быстрее, чем RegExp, если строка2 содержит повторяющиеся шаблоны. В некоторых браузерах indexOf может быть намного медленнее, чем RegExp. Смотрите комментарии.

Редактировать 2: RegExp может быть быстрее, чем indexOf, когда строки очень длинные и / или содержат повторяющиеся шаблоны. Смотрите комментарии и ответ @ Феликса.

Стивен Чунг
источник
но как это сравнить с другими методами? Это самый быстрый или просто один из многих способов сделать это?
Chii
Это должно быть быстро, так как он реализован самим JavaScript (то есть работает нативный код). Любой другой метод, основанный на коде JavaScript, будет медленнее. Если вы знаете точную строку, регулярное выражение может быть немного быстрее (так как движку JavaScript не нужно проходить цепочку прототипов, чтобы найти .indexOf).
Стивен Чунг
Если вам нужен поиск без учета регистра, то вам определенно нужно создать объект RegExp и вызвать его test.
Стивен Чунг
3
Просто запустил тест в Safari. indexOfэто величина медленнее, чем любой другой метод. Так что на самом деле нельзя сказать, какой метод быстрее. Это варьируется от браузера к браузеру.
Феликс Клинг
@ Феликс, это хорошее наблюдение (никогда не доверяй ничему, пока сам не попробуешь)! Я смутно помню что-то, что говорит в строках с большим количеством повторяющихся шаблонов, регулярные выражения должны работать быстрее, чем простая реализация сравнения циклов, потому что регулярные выражения компилируются в конечные автоматы, и они могут отследить намного быстрее, чем простые циклы - которые должны всегда возвращаться назад. трек к следующему персонажу. +1 за проведение эксперимента и его вывод!
Стивен Чунг
17

Быстрейший

  1. (ES6) включает в себя
    var string = "привет",
    substring = "lo";
    string.includes (подстроки);
  1. ES5 и старше indexOf
    var string = "привет",
    substring = "lo";
    string.indexOf (substring)! == -1;

http://jsben.ch/9cwLJ

введите описание изображения здесь

Тинь Нго Куанг
источник
8

В ES6 includes()метод используется для определения, может ли одна строка быть найдена в другой строке, возвращаемой trueили, falseесли необходимо.

var str = 'To be, or not to be, that is the question.';

console.log(str.includes('To be'));       // true
console.log(str.includes('question'));    // true
console.log(str.includes('nonexistent')); // false

Вот спс между

var ret = str.includes('one');

И

var ret = (str.indexOf('one') !== -1);

В результате, показанном в jsperf, кажется, что оба они работают хорошо.

zangw
источник
Могу ли я использовать "регулярное выражение" внутри, как аргумент include? Нравится str.includes("x|y"):; ищите литералы "x" или "y" в одном вызове.
ptkato
@Patrick, согласно включенному документу, вы не можете использовать regexв нем. Одна работа вокруг вашего вопроса,str.includes("x") || str.includes('y')
zangw
В результате улучшений JavaScript в Chrome 59 indexOfон значительно быстрее includes(более 1600% быстрее). Неясно, как разница в 44 млн. Итераций в секунду и 777+ млн. В секунду влияет на производительность в реальном мире, однако мобильные устройства, скорее всего, выиграют достаточно, что indexOfдолжно стать идеальным выбором.
Чад Леви
7

Я обнаружил, что использование простого цикла for, итерации по всем элементам строки и сравнение с использованием charAtвыполняется быстрее, чем indexOfили Regex. Код и подтверждение доступны на JSPerf .

ETA: indexOfи charAtоба работают одинаково ужасно на Chrome Mobile в соответствии с данными Browser Scope, перечисленными на jsperf.com

wpg4665
источник
Странно, что ручная функция лучше встроенной, но я думаю, это потому, что стрелка - это всего лишь один символ. Все еще ...
Мосс
Протестировано в Chrome Mobile 36.0.1985.57 на Apple iPad (iOS 7.1.1). IndexOf быстрее. Извините
rpax
@rpax CharAt по-прежнему значительно быстрее на всех платформах (на основе истории из jsperf), кроме Chrome Mobile, где и IndexOf, и CharAt одинаково плохо работают по сравнению с настольными компьютерами.
wpg4665
1
Я хотел бы посмотреть, как это работает в NodeJS, а также это не очень хороший пример, потому что вы ищете только один символ против подстроки.
qodeninja
Это неверный ответ вообще. Вы не ищете подстроку, только вхождение одного единственного символа
Henrik Myntti
3

Чтобы найти простую строку, используйте метод indexOf () и регулярное выражение - это почти одно и то же: http://jsperf.com/substring - так что выбирайте тот, который легче написать.

чий
источник
1

Это простой способ использовать .match()метод для строки.

var re = /(AND|OR|MAYBE)/;
var str = "IT'S MAYBE BETTER WAY TO USE .MATCH() METHOD TO STRING";
console.log('Do we found something?', Boolean(str.match(re)));

Желаю вам хорошего дня, сэр!

Антон Данильченко
источник
4
Нет причин, matchкогда есть testметод ... Проверьте верхний ответ.
Берги