JavaScript: indexOf против Match при поиске строк?
В отличие от читаемости, существуют ли какие-либо заметные различия (возможно, производительность) между использованием
str.indexOf("src")
и
str.match(/src/)
Я лично предпочитаю match
(и regexp), но коллеги, похоже, идут в другую сторону. Нам было интересно, важно ли это...?
EDIT:
Вначале я должен был сказать, что это для функций, которые будут выполнять частичное согласование простой строки (для получения идентификаторов в атрибутах класса для JQuery), а не для полного поиска регулярных выражений с помощью подстановочных знаков и т.д.
class='redBorder DisablesGuiClass-2345-2d73-83hf-8293'
Таким образом, его различие между:
string.indexOf('DisablesGuiClass-');
VS
string.match(/DisablesGuiClass-/)
Ответы
Ответ 1
RegExp действительно медленнее, чем indexOf (вы можете увидеть его здесь), хотя обычно это не должно быть проблемой. С RegExp вы также должны убедиться, что строка правильно экранирована, что является дополнительной вещью, о которой нужно подумать.
Обе эти проблемы в стороне, если два инструмента делают именно то, что вам нужно, почему бы не выбрать более простой?
Ответ 2
Ваше сравнение может быть не совсем справедливым. indexOf
используется с обычными строками и поэтому очень быстро; match
принимает регулярное выражение - конечно, это может быть медленнее по сравнению, но если вы хотите выполнить регулярное выражение, вы не уйдете далеко с indexOf
. С другой стороны, механизмы регулярного выражения могут быть оптимизированы и в последние годы улучшаются в производительности.
В вашем случае, когда вы ищете стенографическую строку, indexOf
должно быть достаточно. Тем не менее, существует еще одно приложение для регулярных выражений: если вам нужно сопоставить целые слова и хотите избежать совпадений подстрок, тогда регулярные выражения дают вам "якорные граничные привязки". Например:
indexOf('bar')
найдет bar
три раза в bar, fubar, barmy
, тогда как
match(/\bbar\b/)
будет соответствовать только bar
, если он не является частью более длинного слова.
Как вы можете видеть в комментариях, были сделаны некоторые сравнения, которые показывают, что регулярное выражение может быть быстрее, чем indexOf
- если оно критично для производительности, вам может понадобиться профиль вашего кода.
Ответ 3
Если вы пытаетесь найти вхождения подстроки без учета регистра, то match
кажется более быстрым, чем комбинация indexOf
и toLowerCase()
Отметьте здесь - http://jsperf.com/regexp-vs-indexof/152
Ответ 4
Вы спрашиваете, предпочтительнее ли str.indexOf('target')
или str.match(/target/)
. Как предполагали другие плакаты, варианты использования и типы возврата этих методов различны. Первый спрашивает: "Где в str
я могу сначала найти 'target'
?" Второй спрашивает: "str
соответствует регулярному выражению, и если да, то каковы все совпадения для любых связанных групп захвата?"
Проблема заключается в том, что ни один из них не разработан специально для того, чтобы задать более простой вопрос: "содержит ли строка подстроку?" Есть что-то, что явно предназначено для этого:
var doesStringContainTarget = /target/.test(str);
Существует несколько преимуществ использования regex.test(string)
:
- Он возвращает логическое значение, которое вас беспокоит
- Это более результативно, чем
str.match(/target/)
(и соперники str.indexOf('target')
)
- Если по какой-то причине
str
есть undefined
или null
, вы получите false
(желаемый результат) вместо того, чтобы бросать TypeError
Ответ 5
Использование indexOf
должно, теоретически, быть быстрее, чем регулярное выражение, когда вы просто ищете какой-либо простой текст, но вы должны сделать некоторые сравнительные тесты самостоятельно, если вас беспокоит производительность.
Если вы предпочитаете match
, и он достаточно быстро для ваших нужд, идите за ним.
Для чего я согласен с вашими коллегами по этому вопросу: я бы использовал indexOf
при поиске простой строки и использовал match
и т.д. только тогда, когда мне нужна дополнительная функциональность, предоставляемая регулярными выражениями.
Ответ 6
Показатель производительности indexOf
будет, по крайней мере, немного быстрее, чем match
. Все сводится к конкретной реализации. При принятии решения о том, что использовать, задайте себе следующий вопрос:
Будет ли целочисленный индекс достаточным или я нужна функциональность RegExp результат совпадения?
Ответ 7
Возвращаемые значения различаются
Помимо последствий для производительности, которые рассматриваются другими ответами, важно отметить, что возвращаемые значения для каждого метода различны; поэтому методы не могут быть просто заменены без изменения вашей логики.
Возвращаемое значение .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.
}
Ответ 8
всегда используйте indexOf
для существования подстрок и match
только тогда, когда вам это действительно нужно. т.е. если вы искали слово src
в строке, которая также может содержать altsrc
, тогда aString.match(/\bsrc\b/)
действительно более подходит.
Ответ 9
запомнить Internet Explorer 8 не понимает indexOf
.
Но если никто из ваших пользователей не будет использовать ie8 (аналитика Google скажет вам), чем опустить этот ответ.
возможное решение для исправления ie8:
Как исправить Array indexOf() в JavaScript для браузеров Internet Explorer
Ответ 10
Здесь все возможные способы (относительно) поиска строки
//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);
Вот источник: https://koukia.ca/top-6-ways-to-search-for-a-string-in-javascript-and-performance-benchmarks-ce3e9b81ad31
Бенчмарки вроде бы крутили специально для es6 включает, читайте комментарии.
В резюме:
если вам не нужны спички. => Либо вам нужно регулярное выражение и поэтому используйте тест. В противном случае es6 включает или indexOf. Все еще тест против indexOf близки.
И для включает vs indexOf:
Кажется, они одинаковы: https://jsperf.com/array-indexof-vs-includes/4 (если бы это было иначе, это было бы странно, они в основном выполняют то же самое, за исключением различий, которые они выставляют, проверьте это)
И для моего собственного теста. здесь это http://jsben.ch/fFnA0. Вы можете протестировать его (это зависит от браузера) [тестировать несколько раз] здесь, как это выполнялось (многократный запуск indexOf и включает в себя один удар другого, и они близки). Так они одинаковы. [здесь используется та же тестовая платформа, что и в статье выше].
![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: не волнуйтесь, если вы получите непоследовательный результат. Попробуйте другое время и посмотрите, соответствует ли оно или нет. Измените браузер, иногда они просто работают неправильно. Ошибка или плохая обработка памяти. Или что-то.
например:
![enter image description here]()
Здесь также мой тест на jsperf (подробности и обработка графиков для нескольких браузеров)
(верх хромированный)
обычный текст https://jsperf.com/indexof-vs-includes-vs-test-2019
резюме: включает и indexOf имеют одинаковую производительность. тест медленнее.
(кажется, все три выполняют одинаково в chrom)
Длинный текст (в 12 раз длиннее обычного) https://jsperf.com/indexof-vs-include-vs-test-2019-long-text-str/
резюме: все три выполняют одинаково. (хром и 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)
waaaa. Внезапно indexOf стал суперменом. Но, как я уже сказал, я провел тест и посмотрел на количество выборок, которое было около 60. И indexOf, и include, и они выполнили то же самое. Ошибка на jspref. За исключением этого (возможно, из-за проблемы, связанной с ограничением памяти) все остальное было согласованным, оно дает больше подробностей. И вы видите, как много всего происходит в реальном времени.
Окончательное резюме
indexOf против включает => Та же производительность
test => может быть медленнее для коротких строк или текста. И то же самое для длинных текстов. И это имеет смысл для накладных расходов, которые добавляет двигатель регулярных выражений. В хроме это казалось совершенно неважным.