Чому регулярні вирази так хворобливо привабливі?


23

Додаток 1 , виставка 2 , я думаю, вам не складе труднощів згадати інші приклади.

Річ у тому, що якщо існує декілька способів вирішити проблему, програміст PHP (я зазвичай переглядаю тег PHP в StackOverflow) попросить допомоги у вирішенні, що включає регулярні вирази.

Навіть коли це буде менш економічно, навіть коли керівництво по php пропонує ( посилання ) використовувати str_replaceзамість будь-якого preg_*або ereg_*функціонувати, коли не потрібно застосовувати будь-які фантазійні правила заміни.

Хтось має поняття, чому це відбувається?

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


2
Ви можете процитувати, що насправді говорить посібник для php.
ChrisF

1
Тому що вони дурні, тож ви хочете бути членом ексклюзивного клубу kewl kidz? І здебільшого тому, що вони пропонують короткий спосіб вираження матчу чи вилучення, для чого вони створені. Зрозуміло, що для фіктивних випадків, якщо краще, користувальницький синтаксичний розбір, але час розробки над написанням швидкого регексу на користь регексу.
хайлем

Ви підкреслили неправильну частину останнього речення: обурлива частина його "від html", а не "в PHP".
Ізката

Відповіді:


20

Чому регулярні вирази так хворобливо привабливі?

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

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

Крихітна річ, що містить магічну силу. Ви не можете сказати ні, чи не так?


5
+1 - крихітна криптовалюта , не менше.
AJ Johnson

Хобіти хитрі
Бен ДеМотт

49

Коли єдиний у вас інструмент - це регулярний вираз, кожна проблема виглядає так ^((?>[a-zA-Z\d!#$%&'*+\-/=?^_{|}~]+\x20*|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*"\x20*)*(?<angle><))?((?!\.)(?>\.?[a-zA-Z\d!#$%&'*+\-/=?^_{|}~]+)+|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*")@(((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]{2,}|\[(((?(?<!\[)\.)(25[0-5]|2[0-4]\d|[01]?\d?\d)){4}|[a-zA-Z\d\-]*[a-zA-Z\d]:((?=[\x01-\x7f])[^\\\[\]]|\\[\x01-\x7f])+)\])(?(angle)>)$


16
Спокуса обрати цю відповідь настільки сильна, але, мабуть, я повинен протистояти, оскільки це моє перше відкрите запитання тут, і я маю на деякий час уявити серйозність.
cbrandolino

1
@ Дев, це має багато сенсу. Мій коментар був просто нібито смішним способом висловити свою вдячність за відповідь.
cbrandolino

17
Що на землі це відповідає?
Том О'Коннор

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

4
@Tom O'Connor Я думаю, що це щось наближене до Regex для відповідності адреси електронної пошти RFC 2822, але мені довелося витягнути пару символів, оскільки вони спричиняли хаос із відміткою.
гленатрон

23

Я думаю, це тому, що:

  1. Вони фантастично стислі (при правильному використанні) порівняно з еквівалентним кодом та
  2. Вони широко підтримуються різними мовами програмування, тому більшість розробників знайомі з ними.

3
№2 має сенс.
cbrandolino

23

На ранніх етапах моєї кар'єри (тобто до ПНП) я був гуру Перла, і одним з основних аспектів гурудома Перла є оволодіння регулярними виразами.

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

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


2
Я не можу достатньо підтвердити це.
CaffGeek

8
Мені цікаво: чи читаєте ви regexp так вільно, як ви їх пишете?
peterchen

7
Я сподіваюся, що ви проводите регулярні тренінги з регулярного виступу та / або документуєте чорт зі свого коду; інакше ви створюєте кошмар підтримки для своїх колег. Час, який ви заощадили, написавши цей регулярний вираз, може сто разів втратити люди, які намагаються зрозуміти, що робить цей «елегантний регекс».
Джефф Кнехт

3
Так класно. Тут можна почути перетягування між люблячими та ненависними виразками тут, у цих коментарях.
Дан Рей

1
@Ben Lee: Я думаю, що так - OTOH, я ніколи не стикався з коментованим регулярним виразом у дикій природі. Деякі проблеми з регулярними виразами можуть базуватися на ставленні прохолоди.
peterchen

16

Навпаки. Люди папугують, що регулярні виразки є злимими способами ММО занадто часто ІМО. Очевидно, що preg_match надмірно використовується php, але менш очевидно, що це часто доцільно (у PHP).

Я б пішов так далеко і здогадуюсь, що це ще одна мікрооптимізація на землі PHP для використання рядкових функцій. Корисних є багато і багато, і вони, як правило, є кращим вибором. Але не слід уникати preg_matchкількох strposі ifланцюжків. Оскільки на практиці виявляється, libpcre часто швидше, ніж PHP може виконати цикл, шукаючи альтернативні рядки, наприклад

Як недавній приклад змусив мене зрозуміти, перевіряючи, чи є рядок з малих літер:

 if ($string == strtolower($string))

Читає, ніж:

 if (!preg_match("/[A-Z]/", $string))

І ви вважаєте, що перший повинен бути швидшим, оскільки це все-PHP. Але насправді регулярний вираз переглядає рядок лише один раз, і може скасувати заперечне умова, як тільки знайде прописну літеру. Підхід strtolower () однак переглядає рядок двічі. Перший strtolower () робить дублікат рядка шляхом ітерації над кожною літерою, порівнюючи та надруковуючи її. Потім ==повторюється оригінал та копія знову, порівнюючи їх ще раз.

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

(Мені сподобається додати ще одне шахрайство про забавну відповідь @ bobince щодо xhtml-regexes та про те, як останнім часом це часто пов'язується дуже непридатним чином. А більш об'єктивні відповіді нижче залишаються ігнорованими.)


1
Я згоден з вашим прикладом; все ж, у цьому конкретному випадку я б віддав перевагу "strtlower ()" у будь-якому випадку: у некритичному коді навіть така велика (відносно іншої реалізації) оптимізація часу виконання незначна - якщо ви не хочете оцінювати малі регістри, присутність величезного текстового файлу, але я не можу уявити випадок, коли це було б корисно.
cbrandolino

1
@cbrandolino: Ніяких обговорень немає. Цей матеріал повинен бути релевантним і оцінювати лише для вкладених циклів, де це може змінити фактично.
Маріо

4
+1 Насправді люди завжди б'ють їх набагато більше, ніж підтримують.
Увімкнення

1
Як один із "базерів регулярних виразів": Це цікаво бачити однолінійку, яка більш-менш виражає, для чого "ручний" розбір рядків включає 30 рядків. Однак технічне обслуговування страждає від більшості реалістичних прикладів. Крім того, при спробі застосувати їх до неправомірного введення, генерування відповідної діагностики для відхиленого введення вимагає додаткової акробатики. Для мене це прототиповий код "написати тільки" - прикольний для швидких сценаріїв, відстій для довгожителів.
peterchen

1
Кожен, хто не пише всі свої реджекси в /xрежимі, щоб забезпечити пробіл для ліктьової кімнати когнітивного чубку, а також коментарі, щоб пояснити, чому все робиться, слід, звичайно, закрити вуха. Але для справжніх регексів розумної складності вам потрібно розглянути можливість застосування дизайну зверху вниз за допомогою граматичних регексів . Побачивши світло, ви ніколи не повернетесь до нього /@#$^^@#$^&&*)@#/.
tchrist

8

Регулярні вирази дуже привабливі, оскільки вони є найкращим інструментом для розбору звичайної мови.

Вони мають такі переваги:

  • Вони лаконічні . Як правило, потрібно значно більше коду для розбору конкретної регулярної мови, використовуючи певний алгоритм, який ви створили, ніж з регулярним виразом.
  • Вони швидкі у використанні. Як правило, потрібно набагато більше часу, щоб написати аналізатор для певної регулярної мови, використовуючи певний алгоритм, який ви створили, ніж для регулярного вибору.
  • Вони легкі . Після того, як ви дізнаєтесь набір спеціальних символів та їх значень, легко скласти повторне позначення (хоча трохи складніше їх читати). Регенекси - це самі мови - корисна риса, тому що наш вид розвинувся дуже добре в мові.
  • Вони швидкі . Після компіляції вони можуть відповідати довжині рядка Nза час O ( N).
  • Вони гнучкі . Вони можуть відповідати будь-якій звичайній мові, і багато наших даних виражаються як звичайна мова.
  • Вони є всюдисущими . Більшість мов програмування мають базову підтримку регулярного вирівнювання - або через зовнішні бібліотеки, або вбудовані в саму мову. Існує також не дуже велика різниця між самими мовами regexp.

Це робить їх привабливими для ситуацій, до яких вони підходять, але люди можуть використовувати їх у контекстах, де вони не найкращий інструмент, оскільки вони:

  • Не розумійте, що те, що вони відповідають, неможливо виразити за допомогою регулярного вираження (наприклад, HTML).
  • Ліниві (погано) - вони знають інструмент і визнають, що це не найкращий інструмент для того, що вони роблять, але це буде працювати без проблем 95% часу і забирає 95% зусиль, щоб навчитися конкретного аналізатор або написання одного з нуля.
  • Вони не знають, що кращі інструменти існують.

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

Я згоден з рештою, але швидко і легко? Крива навчання крута: для початківців важко розібратися, чому вираз не працює, і кожне впровадження повторних операцій, здається, має принаймні тонкі відмінності, тому вам слід стежити за тим, з чого ви намагаєтесь навчитися.
peterchen

Чому всі плутають витягнення маленьких шматочків HTML з повним аналізом повномасштабної веб-сторінки на дерево повного розбору? Це справді дурно. Повірте, коли я редагую HTML-сторінки vi, ти робиш ставку на своє життя, яке я використовую :%s/foo/bar/gcна ньому. Якщо це досить добре для редактора, це досить добре для сценарію.
tchrist

6

Хммм, я можу лише здогадуватися. Можливо, деякі люди відчули, що 30 рядків їхнього коду було замінено на 20-символьний регулярний вираз, тому їм невірно використовувати що-небудь інше, замість того, коли можна використовувати регулярні вирази.


4

Це відповідає тому, як деякі люди думають. Мені це не подобається, але у мене є друзі, які, здається, думають у регулярних виразах. Я здогадуюсь, що шаблони, що відповідають частині їхнього мозку, більше піддаються, ніж формальна логіка. :-)


6
З точки зору нашої еволюційної історії, яка викликає розум. Ми узгоджували зразки задовго до того, як визначали граматики або виявляли силогізми.
Гленатрон

1
Я не згоден, програмування передбачає відповідність логіки та зразків, дві області. Regexps дуже добре поєднується з малюнком і їх слід використовувати для таких завдань. Занадто сказати: "Мені це не подобається", - це викинути хороший інструмент для певної роботи.
Увімкнення

@Orbling: Питання не в тому, вони хороші чи погані, а чому деякі люди їх надмірно зловживають, а інші - ні.
Леннарт Регебро

Питання може бути, але ваша відповідь передбачає, що той чи інший тип розуму грає, а не обидва.
Увімкнення

Я не думаю, що "запропонувати" це правильне слово.
Леннарт Регебро

3

Я думаю, що всюдисутність регулярного виразку пояснюється всюдисущості рядків. Рядок - це найпростіша структура даних, перша, яку вивчає більшість із нас. Оскільки весь наш код написаний у символічній формі, програміст закономірний розглянути можливість моделювання чогось у символічній формі. Але якщо наша мова програмування чинить опір, коли ми намагаємось розширити його синтаксис для наших розумних нових символічних форм, вони все опиняються між цитатами. Реляційна модель даних має SQL. Модель даних XML має XQuery. Але як щодо скромної моделі даних рядка? Регекс!

Лише вчора я переглядав API, щоб отримати новий блискучий фреймворк Javascript, який підтримує розробку ігор HTML5. Він має декларативний механізм для опису основних підсистем, які знадобляться вашій грі. Як можна вказати ці функції? JSON? Вільне позначення крапок? Масив? Nope - рядок, що містить список імен функцій, розділених комами та пробілами. Цікаво, як він розбирає цей список ...?


2

Тому що ви можете побачити всю справу відразу. Вміючи бачити всю річ, працювати з цим можна легше, і це завжди приємно. Це схоже на причину того, що багато програмістів на C ++ все ще використовують оператори printf: Це не typesafe (хоча gcc принаймні може перевіряти типи у операторах printf), і це не дуже, але хлопчик - це компактний і зручний для використання.

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

Regex, як і будь-який інший потужний інструмент, потрібно використовувати в належному режимі - не занадто багато, не занадто мало. І якщо продуктивність не викликає особливих проблем, одиничний регулярний вираз часом може бути швидшим для запису та простішим налагодженням, ніж ряд рядкових операцій.


2

Хм, нинішні відповіді занадто сильно орієнтуються на технічні аспекти та плюси / мінуси читабельності (що є важливим моментом). Тож дозвольте спробувати перенести це трохи більше на середовище / спільноту PHP:

  • PHP - маленька сестричка Перлса . І невід'ємною частиною Perl є регулярні вирази (вони вигадали цей матеріал, чи не так?). Тому це одна з причин, чому регулярні виразки також поширені в PHP.
  • Випадок використання РНР є збіг не так багато , в відміну від випадку використання регулярних виразів. PHP структурно використовується для склеювання HTML-сторінок. І регепси працюють над текстом. (що сказав WReach)
  • Мікро оптимізація . Як вже згадувалося раніше: люди часто користуються регулярними виразами та / або рядковими функціями PHP після сприйнятої швидкості. Основна проблема в PHP-колах, не характерна для регулярних виразів.
  • Регулярні вирази вбудовані . У Python, у Java, у C #, у Ruby? є доступність, але стримуючий факт, що потрібно завантажувати додатковий модуль. І подивіться, як у PHP або Javascript, де це основна особливість, схема використання відрізняється. Ще один експонат: CSS, де його все частіше використовують.
  • PHP керівництво винне. Це часто є. Регулярні вирази легко виявити, і я відклав цей цікавий факт, тому що це нудно за своєю очевидністю: усі прокляті підручники та книги із введення PHP завжди вчать про регулярні вирази, але не вміють навчатись випадкам використання.
  • Рядок API в PHP був розроблений тими ж самими людьми , які принесли вам чарівні лапки і простору імен \ роздільник. Він охоплює, краще, ніж Java, але не гламурний в цілому. Особливо, якщо рядки можуть подвоюватися як об'єкти (див. Python), функції рядка можуть перевершити регулярні вирази.

Але це так само, як і сторонні ноти. Я вважаю, що це все-таки переважно сприйняття та технічні причини, що призводять до надмірного використання та / або відхилення від регулярних висловлювань взагалі. Тим не менш, PHP та його база даних має кілька властивостей, які його поєднують, і чому ми бачимо більше запитань щодо цього питання (потрібне цитування!), І вони там "болісно привабливі".


1

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

Причина, по якій ви, мабуть, бачите так багато зловживань ними, - це те, що ви переглядаєте розділ PHP StackOverFlow, оскільки я впевнений, що вам відомо, що там багато незрозумілих програмістів PHP PHM.


1

Чому регулярні вирази так хворобливо привабливі?

Їх немає. Вони насправді некрасиві, як пекло. І незбагненне. Вони гидота, яку потрібно вбити якомога швидше.

Тепер, як це було сказано, я повертаюся до налагодження невеликого додатка Perl. Не можу допомогти; на жаль, іноді вони все ще є найкращим інструментом для роботи.


4
Я люблю сказати, що регулярні вирази не є ні "регулярними", ні "експресивними"
Ендрю Барбер

2
Вони некрасиві і незрозумілі, якщо ви їх не розумієте. Як тільки ви досягнете дзен регексу, вони дійсно досить елегантні.
Дан Рей

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

1
@Macneil - Будь ласка, (хоча так, мої думки знаходяться за цією лінією), якщо ви не цитуєте мене, не зазначайте, що я сказав / вирішив щось, чого я не зробив (перша частина вашого коментаря). Що стосується вашого питання, ви вважаєте їх прекрасними ?! ... Я не. А оскільки це суб'єктивний сайт, і це суб'єктивна думка, я не повинен і не бажаю його деталізувати. Не намагаюся з цього приводу.
Грак

1
@Rook - Я думаю, що більшість людей дивляться на складний регулярний вираз, вирішують, що всі регулярні вирази некрасиві, а потім перестають думати. Справа в тому, що вони дуже елегантний і виразний інструмент, якщо ви можете викласти свої забобони щодо них. BTW, за вашою власною логікою, багато програмістів не можуть робити алгебру, тому алгебра, мабуть, сама по собі зла і її слід скасувати, оскільки це явно не дуже зрозуміло.
Дан Рей

0

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


0

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

Проблема полягає в тому, що стандартний регулярному виразі конструкт НЕ Тьюринг-повний , що означає , що є програми , які ви просто не можете реалізувати за допомогою регулярного виразу, і люди не ЗНАЮТЬ , що , коли вони заманили гадану потужністю регулярних виразів.

Це - я здогадуюсь - є причиною jwz-цитати про "тепер у них дві проблеми".

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


0

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


0

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

Те саме можна сказати і про Perl, awk, Linux та все, що не має блискучих кнопок чи симпатичного кольорового синтаксису. Отже, це як додаткова складність "тривіальних завдань", просто киньте певні петлі, розколи, перемикач, якусь магію і все, що може спрацювати. Але добре, якщо ви знаходитесь на іншій стороні дороги, реджекси - це прекрасні різаки для печива, які виглядають як шум сигналу без будь-яких неприємних циклів або більше речей для налагодження. Мені вони подобаються і за гнучкість, яку вони надають. Коли змінюється шаблон відповідності, ви просто змінюєте регулярний вираз, а не алгоритм чи інструмент / що завгодно, і це приємно і знову працювати. А оскільки вони є магічною струною, ви можете розмістити її поза вихідним кодом, якщо бажаєте. І ще одна річ, яка мене змушує замислитись над perl, якщо ви пишете регулярний вираз, який триває більше 20 символів, то відчувається, що ви багато зробили, принаймні для мене це просто так акуратно і компактно. Я також ледачий програміст, мені не подобається писати багато коду з приємним ідентифікацією та коментарями та додавати деякі помилки до суміші.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.