JavaScript: indexOf против совпадения при поиске строк? - PullRequest
60 голосов
/ 21 января 2011

Помимо читабельности, есть ли заметные различия (возможно, производительность) между использованием

str.indexOf("src") 

и

str.match(/src/)

Лично я предпочитаю match (и регулярное выражение), но коллеги, кажется,идти другим путем.Нам было интересно, имеет ли это значение ...?

РЕДАКТИРОВАТЬ:

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

class='redBorder DisablesGuiClass-2345-2d73-83hf-8293' 

Так что разница между:

string.indexOf('DisablesGuiClass-');

VS

string.match(/DisablesGuiClass-/)

Ответы [ 10 ]

54 голосов
/ 21 января 2011

RegExp действительно медленнее, чем indexOf (вы можете видеть это здесь ), хотя обычно это не должно быть проблемой. С RegExp вы также должны убедиться, что строка правильно экранирована, о чем стоит подумать.

Обе эти проблемы в стороне, если два инструмента делают именно то, что вам нужно, почему бы не выбрать более простой?

19 голосов
/ 21 января 2011

Ваше сравнение может быть не совсем справедливым. indexOf используется с простыми строками и поэтому очень быстр; match принимает регулярное выражение - конечно, оно может быть медленнее в сравнении, но если вы захотите выполнить регулярное выражение, вы не доберетесь далеко до indexOf. С другой стороны, механизмы регулярных выражений могут быть оптимизированы, и в последние годы производительность улучшается.

В вашем случае, когда вы ищете дословную строку, indexOf должно быть достаточно. Тем не менее, есть еще одно приложение для регулярных выражений: если вам нужно сопоставить целых слов и вы хотите избежать совпадения подстрок, то регулярные выражения дают вам «якоря границ слов». Например:

indexOf('bar')

найдет bar трижды в bar, fubar, barmy, тогда как

match(/\bbar\b/)

будет соответствовать bar только в том случае, если оно не является частью более длинного слова.

Как вы можете видеть в комментариях, было проведено несколько сравнений, которые показывают, что регулярное выражение может быть быстрее, чем indexOf - если это критично для производительности, вам может потребоваться профилировать ваш код.

9 голосов
/ 07 октября 2014

Если вы пытаетесь найти вхождения подстроки без учета регистра , тогда match кажется быстрее, чем комбинация indexOf и toLowerCase()

Проверьте здесь - http://jsperf.com/regexp-vs-indexof/152

6 голосов
/ 06 июня 2016

Вы спрашиваете, предпочитаете ли str.indexOf('target') или str.match(/target/).Как предлагали другие авторы, варианты использования и типы возврата этих методов различны.Первый спрашивает "где в str я могу сначала найти 'target'?"Вторая спрашивает: «соответствует ли str регулярное выражение и, если да, каковы все совпадения для любых связанных групп захвата?»

Проблема заключается в том, что ни один из них технически не предназначен для того, чтобы задать более простой вопрос »строка содержит подстроку? "Есть что-то, что было специально разработано для этого:

var doesStringContainTarget = /target/.test(str);

Есть несколько преимуществ использования regex.test(string):

  1. . Возвращает логическое значение, о котором вы заботитесь.
  2. Он более производительный, чем str.match(/target/) (и конкуренты str.indexOf('target'))
  3. Если по какой-то причине str равен undefined или null, вы получите false (желаемый результат) вместо броска TypeError
5 голосов
/ 21 января 2011

Использование indexOf в теории должно быть быстрее, чем регулярное выражение, когда вы просто ищете какой-то простой текст, но вы должны сами сделать несколько сравнительных тестов, если вы беспокоитесь о производительности.

Если вы предпочитаете match, и он достаточно быстр для ваших нужд, тогда сделайте это.

Что бы это ни стоило, я согласен с вашими коллегами в этом: я буду использовать indexOf при поиске простой строки и использовать match и т. Д. Только тогда, когда мне понадобятся дополнительные функции, предоставляемые регулярными выражениями.

4 голосов
/ 21 января 2011

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

Достаточно ли будет целочисленный индекс или мне нужна функциональность результата совпадения RegExp?

3 голосов
/ 05 февраля 2019

Здесь все возможные способы (относительно) поиска строки

// 1. включает (введено в ES6)

var string = "string to search for substring",
    substring = "sea";
string.includes(substring);

// 2. string.indexOf

var string = "string to search for substring",
    substring = "sea";
string.indexOf(substring) !== -1;

// 3. RegExp: test

var string = "string to search for substring",
    expr = /sea/;  // no quotes here
expr.test(string);

// 4. string.match

var string = "string to search for substring",
    expr = "/sea/";
string.match(expr);

// 5.string.search

var string = "string to search for substring",
    expr = "/sea/";
string.search(expr);

Здесь src: https://koukia.ca/top-6-ways-to-search-for-a-string-in-javascript-and-performance-benchmarks-ce3e9b81ad31

Бенчмарки, похоже, скручены специально для es6 включает, читайте комментарии.

В резюме:

если вам не нужны спички.=> Либо вам нужно регулярное выражение и поэтому используйте test .В противном случае es6 включает или indexOf .Тем не менее test vs indexOf близки.

И для включений vs indexOf:

Они кажутся одинаковыми: https://jsperf.com/array-indexof-vs-includes/4(если бы это было иначе, это было бы странно, они в основном выполняют то же самое, за исключением различий, которые они выставляют проверьте это )

И для моего собственного теста производительности.здесь это http://jsben.ch/fFnA0 Вы можете проверить это (это зависит от браузера) [протестировать несколько раз] здесь, как это выполнялось (многократный запуск indexOf и включает в себя один удар другому, и они близки).Так они одинаковы.[здесь используется та же тестовая платформа, что и в статье выше].

enter image description here enter image description here

А здесь для длинного текставерсия (в 8 раз длиннее) http://jsben.ch/wSBA2

enter image description here

Протестировано и Chrome, и Firefox, тоже самое.

Обратите внимание на jsben.ch нене обрабатывает переполнение памяти (или там правильно ограничивает. Оно не показывает никакого сообщения), поэтому результат может быть неправильным, если вы добавите более 8 дубликатов текста (8 работают хорошо).Но вывод для очень большого текста - все три работают одинаково.В противном случае для коротких indexOf и include одинаковы и тестировать немного медленнее.или Может быть таким же, как и в chrome (Firefox 60 медленнее).

Обратите внимание на jsben.ch: не волнуйтесь, если получите противоречивый результат.Попробуйте другое время и посмотрите, соответствует ли оно или нет.Измените браузер, иногда они просто работают неправильно.Ошибка или плохая обработка памяти.Или что-то еще.

ex:

enter image description here

Здесь также мой тест на jsperf (более подробная информация и обработка графиков для нескольких браузеров)

(верх хромированный)

обычный текст https://jsperf.com/indexof-vs-includes-vs-test-2019
резюме: включает и indexOf имеют одинаковую производительность.тест медленнее.

enter image description here enter image description here (кажется, что все три выполняют одно и то же в chrom)

Длинный текст (12время дольше обычного) https://jsperf.com/indexof-vs-includes-vs-test-2019-long-text-str/
резюме: Все три работают одинаково.(chrome и firefox) enter image description here

очень короткая строка https://jsperf.com/indexof-vs-includes-vs-test-2019-too-short-string/
резюме: включает и indexOf выполняют то же самое итест медленнее.

enter image description here

Примечание: о бенчмарке выше.Для очень короткой строки версия (jsperf) имела большую ошибку для chrome.Видя моими глазами.около 60 выборок было выполнено для обоих indexOf и включает в себя один и тот же способ (повторяется много раз).И тест немного меньше и так медленнее.не обманывайтесь неправильным графиком.Это ясно не так.Тот же тест работает нормально для Firefox, конечно, это ошибка.

Вот иллюстрация: (первое изображение было тестом на Firefox) enter image description here Ваааа.Внезапно indexOf стал суперменом.Но, как я уже сказал, я сделал тест и посмотрел на количество образцов, оно было около 60. И indexOf, и include, и они выполнили то же самое.Ошибка в jspref .За исключением этого (возможно, из-за проблемы, связанной с ограничением памяти) все остальное было согласованным, оно дает больше подробностей.И вы видите, сколько простых происходит в режиме реального времени.

Окончательное резюме

indexOf против включает => Та же производительность

test => может быть медленнее для коротких строк или текста.И то же самое для длинных текстов.И это имеет смысл для накладных расходов, которые добавляет двигатель регулярных выражений.В хроме это казалось совершенно неважным.

3 голосов
/ 10 мая 2016

Возвращаемые значения отличаются

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

Возвращаемое значение .indexOf: integer

Индекс в вызывающем String объекте первого появления указанного значения, начиная поиск с fromIndex.
Возвращает -1, если значение не найдено.

Возвращаемое значение .match: array

Массив, содержащий весь результат совпадения и все сопоставленные результаты в скобках.
Возвращает null, если совпадений не было .

Поскольку .indexOf возвращает 0, если вызывающая строка начинается с указанного значения, простой верный тест не пройден.

Например:

Учитывая этот класс…

class='DisablesGuiClass-2345-2d73-83hf-8293 redBorder' 

… возвращаемые значения для каждого будут отличаться:

//  returns `0`, evaluates to `false`
if (string.indexOf('DisablesGuiClass-')) {
    … // this block is skipped.
}

против

//  returns `["DisablesGuiClass-"]`, evaluates to `true`
if (string.match(/DisablesGuiClass-/)) { 
    … // this block is run.
}

Правильный способ запустить верный тест с возвратом из .indexOf - это проверить против -1:

if (string.indexOf('DisablesGuiClass-') !== -1) {
//  ^returns `0`                        ^evaluates to `true`
    … // this block is run.
}
0 голосов
/ 20 марта 2017

помните, Internet Explorer 8 не понимает indexOf. Но если никто из ваших пользователей не использует ie8 (Google Analytics скажет вам), то пропустите этот ответ. Возможное решение для исправления ie8: Как исправить Array indexOf () в JavaScript для браузеров Internet Explorer

0 голосов
/ 21 января 2011

всегда используйте indexOf для существования подстрок и match только тогда, когда вам это действительно нужно.то есть, если вы искали слово src в строке, которая также может содержать altsrc, тогда aString.match(/\bsrc\b/) действительно более уместно.

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