Як це працює?
Погляньте на теорію автоматів
Коротше кажучи, кожен регулярний вираз має еквівалентний кінцевий автомат і може бути складений та оптимізований до кінцевого автомата. Задіяні алгоритми можна знайти в багатьох книгах-компіляторах. Ці алгоритми використовуються програмами unix, такими як awk та grep.
Однак у більшості сучасних мов програмування (Perl, Python, Ruby, Java (та на базі JVM мов), C #) не використовується такий підхід. Вони використовують рекурсивний підхід зворотного відстеження, який збирає регулярне вираження в дерево або послідовність конструкцій, що представляють різні підряди регулярного виразу. Більшість сучасних синтаксисів "регулярного вираження" пропонують зворотні посилання, які знаходяться поза групою регулярних мов (вони не мають представлення в кінцевих автоматиках), які тривіально реалізовані в рекурсивному підході до зворотного відстеження.
Оптимізація зазвичай дає більш ефективну машину. Наприклад: розгляньте aaaab | aaaac | aaaad, звичайний програміст може отримати просту, але менш ефективну реалізацію пошуку (порівняння трьох рядків окремо) прямо за десять хвилин; але розуміючи, що це еквівалентно aaaa [bcd], кращий пошук можна здійснити шляхом пошуку спочатку чотирьох "a", а потім протестуйте 5-й символ на [b, c, d]. Процес оптимізації був одним із моїх домашніх робіт із компілятора багато років тому, тому я припускаю, що він є і в більшості сучасних двигунів регулярної експресії.
З іншого боку, державні машини мають певну перевагу, коли вони приймають рядки, оскільки вони використовують більше місця в порівнянні з "тривіальною реалізацією". Розглянемо програму для скасування котирування на рядках SQL, тобто: 1) починається та закінчується одинарними лапками; 2) Одиночні лапки виходять двома послідовними цитатами. Отже: вхід ['a' ''] повинен дати вихід [a ']. За допомогою машини машини послідовними одинарними лапками обробляються два штати. Ці два стани служать метою запам'ятовування історії введення таким чином, що кожен символ введення обробляється рівно лише один раз, як показано нижче:
...
S1->'->S2
S1->*->S1, output *, * can be any other character
S2->'->S1, output '
S2->*->END, end the current string
Отже, на мою думку, регулярне вираження може бути повільнішим у деяких тривіальних випадках, але зазвичай швидше, ніж алгоритм пошуку, створений вручну, враховуючи той факт, що оптимізація не може бути надійно виконана людиною.
(Навіть у тривіальних випадках, таких як пошук рядка, розумний двигун може розпізнати єдиний шлях на карті стану і звести цю частину до простого порівняння рядків та уникнути управління станами.)
Конкретний двигун з фреймворку / бібліотеки може бути повільним, оскільки двигун робить купу інших речей, які програміст зазвичай не потребує. Приклад: клас Regex в .NET створює купу об'єктів, включаючи Match, Group та Captures.