Як насправді працюють регулярні вирази?


30

Скажіть, у вас є документ із написаним есе. Ви хочете розібрати цей твір, щоб вибрати лише певні слова. Класно.

Чи використовувати регулярний вираз швидше, ніж розбирати файл рядок за рядком і слово за словом шукати відповідність? Якщо так, то як це працює? Як можна піти швидше, ніж дивитися на кожне слово?


5
Ви припускаєте (маючи на увазі нульові докази), що регулярний вираз стане швидшим, але ви не знаєте, чому це? Можливо, тоді слід переглянути свої припущення.
pdr

3
таким чином, припущення. якби у мене були докази, це не було б одне, правда?
lazeR

4
Це не сенс. Справа в тому, що призвело вас до цього припущення ... Вам не потрібні докази для ваших питань, але вам потрібні міркування для ваших припущень.
янніс

1
Помилка, чи не кожен символ рядка введення просто переміщує машину стану до наступного стану. Я не бачу, як хтось може зробити цю операцію повільно ...
tp1

2
Я не впевнений у швидшому, але моя головна причина використання регулярних виразів полягає в елегантності складних шаблонів відповідності, ви просто не знайдете кращого способу сформулювати це в середовищі кодування.
Манторок

Відповіді:


47

Як це працює?

Погляньте на теорію автоматів

Коротше кажучи, кожен регулярний вираз має еквівалентний кінцевий автомат і може бути складений та оптимізований до кінцевого автомата. Задіяні алгоритми можна знайти в багатьох книгах-компіляторах. Ці алгоритми використовуються програмами 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.


2
Я не міг би сказати це краще сам. Єдине, що я хотів би додати: Регулярні вирази також можуть компенсувати лінивих програмістів. У цьому прикладі ви згадали aaaab|aaaac|aaaadVS. aaaa[bcd]. Варто чітко заявити, що обидві математично рівноцінні і виробляють однакові DFA, тим самим надаючи програмістам більше свободи представляти регулярний вираз таким чином, що має сенс (не те, що це звичайна практика, але ... y'know). ..
riwalk

Дякую, це насправді мало сенс завдяки класу автомати, який я взяв
lazeR

Це приклад тривіальної задачі , де регулярний вираз є надмірністю?: Stackoverflow.com/questions/18955099 / ...
Menelaos Bakopoulos

17

Регулярні вирази просто виглядають швидко, оскільки у вас швидкі комп’ютери.

Ще в 1980-х, коли 1 MIPS був швидким комп'ютером, регулярні вислови були досить великою областю хвилювань, занепокоєнь та досліджень, оскільки вони були повільними та негарними та обчислювали інтенсивно. Розумна розробка алгоритму слідувала і допомагала - але для всіх практичних цілей сьогодні ви бачите диво, як швидкі машини обробляють тріщини.


2
Якщо ви просто шукаєте одне слово, обидва способи однакові (або regexp трохи повільніше). Але, враховуючи складний вираз (і текст досить великого розміру), звичайний вираз, ймовірно, буде швидшим, ніж простий пошук (якщо припустити, що ви просто пишете простий пошук (ви завжди можете написати складний пошук, який є настільки швидким)). Зараз важлива погода - це надто загальне питання, і вам доведеться розглядати це в кожному конкретному випадку.
Мартін Йорк

3
-1. Теорія регулярного вираження бере початок з 50-х років і мала важливу роль у створенні лексичних аналізаторів (і за їх розширенням, укладачів). Вони створюють дуже ефективні державні машини, які (доцільно) використовують найменшу кількість можливих станів. Отримані державні машини можуть відповідати складним шаблонам набагато швидше, ніж все, що ви могли написати вручну. Вони виглядають швидко, тому що вони швидкі.
riwalk

Можливо, трохи пропустили мою думку. Вони можуть бути "швидкими", але це все відносно - попереду ще купа роботи. Деякі з інших відповідей тут також читають.
quick_now

Чи відповідає ця відповідь на питання? і як 13 грошей?
Садананд

7

Чому, на вашу думку, вони швидші, ніж пошук документа?

Ви можете виконати кілька хитрощів, наприклад. якщо ви шукаєте слово з 10 літер, що починається з A і закінчується на B, то якщо ви знайдете A і позицію символу 9 далі не B, ви можете пропустити деякі. див. алгоритм Кнута – Морріса – Пратта


5

Що робить регулярний вираз швидким?

Насправді їх немає. Не так багато. Просто вони недостатньо повільні, щоб більшість із нас помітили. Ще в "старих повільних днях" це було набагато помітніше.

Вони також не є правильним інструментом для кожної роботи - молотком .


+1 Дякую, що нагадали мені про той конкретний витвір мистецтва ...
Янніс

5

RegEx порівняно швидше коду, який ви можете написати, тому що більшість бібліотек є результатом того, що багато розробників витрачають багато років, оптимізуючи їх, щоб вичавити кожну останню можливу ефективність. Одному особі важко дублювати це у власному коді пошуку.


4
s / писк / стискання /?
Péter Török

4

Ваша основна передумова неправильна.

Регулярні вирази не завжди швидші, ніж простий пошук. Все залежить від контексту. Це залежить від складності виразу, довжини документа, який шукається, і цілого ряду факторів.

Що відбувається, так це те, що регулярний вираз буде зібраний у простий парсер (на який потрібен час). Таким чином, якщо документ невеликий, цей додатковий час буде переважувати будь-яку перевагу. Крім того, якщо вираз простий, то регулярний вираз не дасть вам жодної переваги.

Якщо вираз складний і документ досить великий, то можна отримати певну користь. Чи буде це досить важливим, щоб вважати регулярні вирази швидшими, залежатиме багато від того, скільки зусиль ви хочете докласти до пошуку (також регулярні вирази можуть мати певні оптимізації, які бібліотека могла б забезпечити, що ви б не думали про себе).

Що я намагаюся сказати, це те, що немає узагальненої, ковдрої відповіді. Якщо у вас був конкретний вираз (і відомий розмір документа), ви можете сказати, що отримаєте відповідь так / ні про те, чи буде вираз швидшим, ніж простий пошук (і чому).

Справжня перевага регулярних виразів полягає в тому, що раз ви зрозумієте, як їх записати, можливість висловити складний пошук стислим способом. Оскільки це узагальнена форма, ви можете потім будувати інструменти, які дозволяють здійснювати пошук способом, який корисний у загальному випадку; Зазвичай це як мінімум так само швидко, як простий пошук (на документах мінімального розміру; на документах менших розмірів це не має значення, оскільки навіть якщо він повільніше, він все ще досить швидкий).


1

Імовірно, що в деяких мовах високого рівня (можливо, JavaScript) використання бібліотеки регулярних виразів, реалізованої мовою низького рівня (можливо, C), було б швидше, ніж написання логіки синтаксичного аналізу на мові високого рівня.

Правдоподібно - я поняття не маю, чи справді це взагалі так.


Хороший! Це те, що я теж вважав. Але коли сьогоднішні процесори проходять швидше, ніж його попередники, я сміливо можу сказати, що якщо ви ефективно пишете код, ви рідко зможете сказати відмінності. Я насправді в цілому не дуже гагаю за весь регулярний вираз швидшої гіпотези! ;-)
користувач3833732
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.