Если у вас есть экземпляр регулярного выражения JavaScript (неважно, как вы его создаете), который вы хотите использовать повторно, чтобы вам не приходилось заново создавать его при каждом использовании, остерегайтесь, особенно если вы используете ' флаги g или y. Существует множество примеров, в которых используется флаг «g», и на первый взгляд это может звучать хорошо — найти все совпадения. Даже regex101.com по умолчанию использует флаг «gm».

Учитывая, что регулярные выражения сами по себе относительно сложны, и лишь немногие разработчики (включая меня) полностью разбираются в них, вы наверняка можете обнаружить, что используете флаг вроде 'g', не задумываясь об этом, а затем почесываете голову, когда это не так. Работа.

Причина этого в том, что экземпляр поддерживает индекс последнего совпадения после каждого использования test или exec — даже для совершенно разных строк. Документы объясняют, что это состояние. Имеет смысл, что он не знает, что вы даете ему разные строки. Кажется, это было задумано так, что вы будете многократно вызывать exec (или, я думаю, test) для одной и той же строки снова и снова.

В настоящее время у нас есть string.match и string.matchAll, и они дают вам массив совпадений, поэтому вас можно простить за мягкое предположение, что exec работает таким образом, и этот тест более или менее проигнорирует этот флаг.

Рассмотрим этот пример:

const searchTester = new RegExp(searchText, 'gi');
let matchingOptions = allOptions.filter(o => searchTester.test(o.text));

Теперь рассмотрите следующие варианты:

Восточный Лас-Вегас
Лас-Вегас
Северный Лас-Вегас

Если бы вы не были на флаге «g» или, может быть, не думали об этом, и вы искали бы «las», вы бы ожидали найти все три, верно? Ну, ты не будешь. Потому что после поиска в восточном Лас-Вегасе для lastIndex будет установлено значение 5. И когда он перейдет к поиску в Лас-Вегасе, он не найдет его, потому что он начинается с 5. Это сбросит lastIndex в 0, и тогда он будет соответствовать северу. Лас Вегас. Таким образом, вы не найдете наиболее вероятное совпадение! Веселье!

Теперь, если вы отлаживаете это и просто набираете в консоли:

/las/gi.test('Лас-Вегас')

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

Подводить итоги:

  • Если вам просто нужно проверить, есть ли любое совпадение, вы можете безопасно опустить флаг g. Вы также можете вручную сбросить lastIndex, но зачем? :)
  • Если вам нужно получить все фактические совпадения, возможно, вместо этого используйте String.match или .matchAll. Это кажется более разумным, если вы еще не привыкли к RegExp.
  • В противном случае создайте цикл и сами соберите все совпадения, используя одну и ту же строку.