Чи є конкретна причина поганої читабельності синтаксису регулярного вираження?


160

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

Ми всі згодні, що selfDocumentingMethodName()це набагато краще, ніж e(). Чому це не слід застосовувати і до регулярних виразів?

Мені здається, що замість проектування синтаксису однорядкової логіки без структурної організації:

var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})(0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;

І це навіть не суворий аналіз URL-адреси!

Натомість ми можемо зробити структуру трубопроводів організованою та читаною для базового прикладу:

string.regex
   .isRange('A-Z' || 'a-z')
   .followedBy('/r');

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


Коментарі не для розширеного обговорення; ця розмова переміщена до чату .
maple_shaft

1
Я намагався вирішити саме цю проблему читабельності за допомогою бібліотеки під назвою RegexToolbox. Поки він перенесений на C #, Java та JavaScript - див. Github.com/markwhitaker/RegexToolbox.CSharp .
Марк Уітакер

було зроблено багато спроб вирішити це питання, але культуру важко змінити. дивіться мою відповідь про словесні вирази тут . Люди досягають найменшого доступного інструменту.
Паривар Сараф

Відповіді:


178

Є одна велика причина, чому регулярні вирази були розроблені настільки ж лаконічними, як вони є: вони були розроблені для використання як команди редактору коду, а не як мова для кодування. Точніше, це edбула одна з перших програм, що використовували регулярні вирази , і звідти регулярні вислови розпочали завоювання світового панування. Наприклад, edкоманда g/<regular expression>/pнезабаром надихнула окрему програму під назвою grep, яка використовується і сьогодні. Через свою силу вони згодом були стандартизовані та використовувалися в різних інструментах, таких як sedіvim

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


5
Регекс не призначений для розбору. в іншому випадку stackoverflow.com/questions/1732348/… . і головні болі.
njzk2

19
@ njzk2 Ця відповідь насправді неправильна. HTML документ не є регулярним мовою, але HTML відкритим тег , який є те , що питання стосується, на самому ділі.
Випадково832

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

13
Тож для тих, хто думає, що grepце неправильно "хапання", це насправді з g/ re(для регулярного вираження) / p?
Хаген фон Ейтцен

6
@DannyPflughoeft Ні, це не так. Відкритий тег просто <aaa bbb="ccc" ddd='eee'>, всередині нього немає вкладених тегів. Ви не можете вкладати теги, те, що ви вкладаєте, - це елементи (відкритий тег, вміст, включаючи дочірні елементи, тег закриття), який у питанні не задавали питання про розбір. Теги HTML - це звичайна мова - балансування / вкладення відбувається на рівні вище тегів.
Випадково832

62

Регулярний вираз, який ви цитуєте, - це жахливий безлад, і я не думаю, що хтось погоджується, що це читається. У той же час, значна частина цієї потворності притаманна проблемі, що вирішується: Є кілька шарів вкладання, а граматика URL є досить складною (звичайно, надто складною для спілкування на будь-якій мові). Однак, безумовно, правда, що є кращі способи описати, що описує цей регулярний вираз. То чому їх не використовують?

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

Незважаючи на це, регулярні вирази часто зловживають, тобто застосовуються навіть тоді, коли інший інструмент буде набагато кращим. Я не думаю, що синтаксис регулярних виразів є жахливим . Але це очевидно набагато краще за короткими та простими зразками: архетипний приклад ідентифікаторів на мовах, подібних С, [a-zA-Z_][a-zA-Z0-9_]*можна читати з абсолютним мінімумом знань про регулярне вираження, і коли ця смуга буде досягнута, вона одночасно є очевидною і красивою. Вимагати меншої кількості символів не є по суті поганим, зовсім навпаки. Бути лаконічним є чеснотою за умови, що ти залишаєшся зрозумілим.

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

То чому вони стискаються в більш складних випадках? Я бачу три основні проблеми:

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

    # This is not equivalent to the regex in the question
    # It's just a mock-up of what a grammar could look like
    url      ::= protocol? '/'? '/'? '/'? (domain_part '.')+ tld
    protocol ::= letter+ ':'
    ...
    
  2. Як ми могли бачити вище, пробіл, який не має особливого значення, корисний для дозволення форматування, яке простіше для очей. Те саме з коментарями. Регулярні вирази не можуть цього зробити, оскільки пробіл - це саме те, що є буквальним ' '. Однак зауважте: деякі реалізації дозволяють "багатослівний" режим, коли пробіл ігнорується та можливі коментарі.

  3. Немає мета-мови для опису загальних зразків та комбінаторів. Наприклад, можна написати digitправило один раз і продовжувати використовувати його в контекстній вільній граматиці, але не можна визначити "функцію", так би мовити, що дається виробництву pі створює нову продукцію, яка робить щось додаткове з нею, наприклад створити виробництво для відокремленого комою списку подій p.

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

Рішення для цих випадків існують. Існує приблизно десять тисяч бібліотек комбінаторів парсера, які роблять приблизно те, що ви пропонуєте, лише з різним набором операцій, часто різним синтаксисом, і майже завжди з більшою силою розбору, ніж регулярні вирази (тобто вони мають справу з контекстними мовами або деякими значущими підмножина тих). Потім є генератори аналізаторів, які працюють із описаним вище підходом "використовувати кращий DSL". І завжди є можливість записати частину розбору вручну у відповідному коді. Ви навіть можете змішувати і співставляти, використовуючи регулярні вирази для простих підзадач і виконуючи складні речі в коді, що викликає регекси.

Я не знаю достатньо про перші роки обчислень, щоб пояснити, як регулярні вирази стали настільки популярними. Але вони тут, щоб залишитися. Вам просто потрібно використовувати їх розумно, а не використовувати їх, коли це мудріше.


9
I don't know enough about the early years of computing to explain how regular expressions came to be so popular.Однак ми можемо загрожувати здогадками: базовий механізм регулярного вираження дуже простий у здійсненні, набагато простіше, ніж ефективний аналог без контексту.
biziclop

15
@biziclop Я не переоцінював цю змінну. Yacc, який, мабуть, мав достатню кількість попередників, щоб його називали " ще одним компілятором компілятора", був створений на початку 70-х років, і він був включений в Unix версією до цього року grep(Версія 3 проти Версії 4). Здається, перше основне використання

Я можу продовжувати лише те, що знайшов у Вікіпедії (тому я б не повірив, що це 100%), але відповідно до цього, yaccбула створена в 1975 році вся ідея парсерів LALR (які входили до першого класу практично придатних аналізаторів своїх вид) зародився в 1973 р., тоді як перша реалізація двигуна regexp, в якій JIT зібрав вирази (!), була опублікована в 1968 році. Але ви праві, важко сказати, що замахнулося, насправді важко сказати, коли реджекси почали "приймати" вимкнено ". Але я б підозрював, що коли їх помістили в текстові редактори, які використовували розробники, вони також хотіли використовувати їх у власному програмному забезпеченні.
biziclop

1
@ jpmc26 відкрити свою книгу, JavaScript Хороші частини до розділу Регекс.
Візіонер

2
with very few differences between dialectsЯ б не сказав, що це "дуже мало". Будь-який заздалегідь визначений клас символів має кілька визначень між різними діалектами. А також є прискіпливі розбори, характерні для кожного діалекту.
nhahtdh

39

Історична перспектива

Стаття у Вікіпедії досить докладно про походження регулярних виразів (Kleene, 1956). Оригінальний синтаксис був відносно простий тільки *, +, ?, |і угрупування (...). Це було лаконічно ( і читати, обидві не обов'язково проти), оскільки формальні мови, як правило, виражаються стислими математичними позначеннями.

Пізніше синтаксис та можливості розвивалися у редакторів і зростали разом з Perl , який намагався бути стислим за дизайном ( "загальні конструкції повинні бути короткими" ). Це сильно ускладнило синтаксис, але зауважте, що люди зараз звикли до регулярних виразів і добре пишуть (якщо не читають) їх. Те, що вони іноді пишуть, лише підказує, що коли вони занадто довгі, вони, як правило, не є правильним інструментом. Регулярні вирази, як правило, не читаються при зловживанні.

Поза рядковими регулярними виразами

Говорячи про альтернативні синтаксиси, давайте подивимось на той, який вже існує ( cl-ppcre , у загальному Lisp ). Ваш довгий регулярний вираз можна проаналізувати ppcre:parse-stringтаким чином:

(let ((*print-case* :downcase)
      (*print-right-margin* 50))
  (pprint
   (ppcre:parse-string "^(?:([A-Za-z]+):)?(\\/{0,3})(0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$")))

... і призводить до такої форми:

(:sequence :start-anchor
 (:greedy-repetition 0 1
  (:group
   (:sequence
    (:register
     (:greedy-repetition 1 nil
      (:char-class (:range #\A #\Z)
       (:range #\a #\z))))
    #\:)))
 (:register (:greedy-repetition 0 3 #\/))
 (:register
  (:sequence "0-9" :everything "-A-Za-z"
   (:greedy-repetition 1 nil #\])))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\:
    (:register
     (:greedy-repetition 1 nil :digit-class)))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\/
    (:register
     (:greedy-repetition 0 nil
      (:inverted-char-class #\? #\#))))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\?
    (:register
     (:greedy-repetition 0 nil
      (:inverted-char-class #\#))))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\#
    (:register
     (:greedy-repetition 0 nil :everything)))))
 :end-anchor)

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

Однак якщо у вас виникають проблеми з регулярними виразами, перетворення їх у цей формат може допомогти вам розшифрувати та налагодити код. Це одна перевага перед строковими форматами, де одну помилку символів важко помітити. Основна перевага цього синтаксису - маніпулювати регулярними виразами, використовуючи структурований формат, а не кодування на основі рядків. Це дозволяє складати та будувати такі вирази, як будь-яка інша структура даних у вашій програмі. Коли я використовую вищевказаний синтаксис, це, як правило, тому, що я хочу створювати вирази з менших частин (див. Також мою відповідь CodeGolf ). Для вашого прикладу ми можемо написати 1 :

`(:sequence
   :start-anchor
   ,(protocol)
   ,(slashes)
   ,(domain)
   ,(top-level-domain) ... )

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

Зауважте також, що вищевказана форма дозволяє (:regex "string")форми, щоб ви могли змішувати стислі позначення з деревами. Все це призводить ІМХО до доброї читабельності та зручності комбінування; в ньому розглядаються три проблеми, виражені делнан , опосередковано (тобто не мовою самих регулярних виразів).

Прийти до висновку

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

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

  • Крім того, формальні граматики легше читаються і краще називають підметами і абстрагуванням. Термінали, як правило, виражаються як прості регулярні вирази.


1. Ви можете віддати перевагу формуванню виразів у режимі читання, оскільки регулярні вирази, як правило, є константами програми. Дивіться create-scannerта load-time-value:

'(:sequence :start-anchor #.(protocol) #.(slashes) ... )

5
Можливо, я просто звик до традиційного синтаксису RegEx, але я не настільки впевнений, що 22 дещо читабельні рядки легше зрозуміти, ніж рівнозначний один рядковий регекс.

3
@ Dan1111 «кілька популярних» ;-) Добре, але якщо вам потрібно мати дійсно довге регулярний вираз, то має сенс визначити підмножини, як digits, identі складати їх. Як я вважаю, це робиться, як правило, за допомогою стринг-маніпуляцій (конкатенація чи інтерполяція), що призводить до інших проблем, таких як правильне втеча. \\\\`Наприклад, пошук випадків у пакунках emacs. До речі, це ще гірше , тому що той же екранує символ використовується як для спеціальних символів , як \nі \"і для регулярних виразів синтаксису \(. Приклад непогашеного синтаксису - це невідповідний текст printf, де %dце не суперечить \d.
coredump

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

@ dan1111 Я погоджуюся, що багатослівність сама по собі не є вдосконаленням. Що може бути вдосконаленням - це маніпулювання регулярним виразом за допомогою структурованих даних замість рядків.
coredump

@ dan1111 Можливо, я повинен запропонувати редагування за допомогою Haskell? Парсек робить це лише за дев'ять рядків; як однострочнікі: do {optional (many1 (letter) >> char ':'); choice (map string ["///","//","/",""]); many1 (oneOf "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-."); optional (char ':' >> many1 digit); optional (char '/' >> many (noneOf "?#")); optional (char '?' >> many (noneOf "#")); optional (char '#' >> many (noneOf "\n")); eof}. У кілька рядків , як позначає довгий рядок , як domainChars = ...і section start p = optional (char start >> many p)це виглядає досить просто.
CR Drost

25

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

Порівняйте регекс з BNF . Його синтаксис не набагато чистіший за регулярний вираз, але він використовується інакше. Ви починаєте з визначення простих названих символів і складаєте їх до тих пір, поки не з’явиться символ, що описує весь візерунок, який ви хочете зіставити.

Наприклад, подивіться на синтаксис URI в rfc3986 :

URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
hier-part     = "//" authority path-abempty
              / path-absolute
              / path-rootless
              / path-empty
...

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


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


12

selfDocumentingMethodName () набагато краще, ніж e ()

є це? Існує причина, що більшість мов мають {and} як розділові обмежувачі блоків, а не BEGIN і END.

Людям подобається лаконічність, і коли ви знаєте синтаксис, коротка термінологія краще. Уявіть ваш приклад регулярного вираження, якби d (для цифри) було "цифрою", регулярний вираз було б ще більш жахливим для читання. Якби ви зробили це більш легко розбірливим з керуючими символами, то це буде більше схоже на XML. Ні один із них не є гарним, як тільки ви знаєте синтаксис.

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


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

1
@ Левшенко: Ви стверджуєте, що e()це краще, ніж selfDocumentingMethodName()?
ЖакБ

3
@JacquesB, можливо, не у всіх контекстах (наприклад, глобальна назва). Але для ретельно складених речей? Майже напевно. Однозначно частіше, ніж говорить звичайна мудрість.
Левшенко

1
@ Левшенко: Мені важко уявити контекст, якщо назва функції однієї букви краще, ніж більш описове ім'я. Але я думаю, це чиста думка.
ЖакБ

1
@MilesRout: приклад насправді для e()проти самостійного документування методи імені. Чи можете ви пояснити, в якому контексті вдосконалення використовувати однобуквені назви методів, а не описові назви методів?
ЖакБ

6

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

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

Люди рідко використовували параметри регулярного вираження. Багато мов пропонують вам функції перевірки довжини рядка або розділення числових частин від нього. Ви можете використовувати рядкові функції для нарізки текстів та їх реформування. Сила регулярного вираження помічається, коли ви використовуєте складні форми для виконання дуже конкретних складних завдань.

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

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


2

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

Наприклад, рядок регулярного вираження для URL-адреси можна зменшити приблизно:

UriRe = [scheme][hier-part][query][fragment]

до:

UriRe = UriSchemeRe + UriHierRe + "(/?|/" + UriQueryRe + UriFragRe + ")"
UriSchemeRe = [scheme]
UriHierRe = [hier-part]
UriQueryRe = [query]
UriFragRe = [fragment]

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


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

1
Інші мови повинні наздогнати Perl 5 у підтримці "сумісного регулярного виразу" з Perl. Підвиразки не є тим самим, що просто об'єднувати рядки специфікації регулярних виразів. Захоплення слід називати, не покладаючись на неявну нумерацію.
JDługosz

0

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

Perl робить досить слабку спробу зробити їх читабельнішими, надаючи пробіли та коментарі, але не робить нічого віддаленого образного.

Є й інші синтаксиси. Хорошим є синтаксис scsh для регулярних виразів , який, на мій досвід, створює регулярні виразки, які досить легко набрати, але все ще читаються після факту.

[ scsh чудовий з інших причин, лише однією з яких є його відомий текст підтвердження ]


2
Perl6 робить! Подивіться на граматики.
JDługosz

@ JDługosz Наскільки я бачу, це більше схоже на механізм генераторів парсера, а не на альтернативний синтаксис для регулярних виразів. Але відмінність, можливо, не є глибокою.
Норман Грей

Це може бути заміною, але не обмежуватись однаковою потужністю. Ви можете перевести regedp у вбудовану граматику з 1 до 1 відповідності модифікаторів, але у більш читаному синтаксисі. Приклади, що рекламують її як таку, є в оригінальній Апокаліпсисі Perl.
JDługosz

0

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

Ви, наприклад regex.isRange(..).followedBy(..), поєднали синтаксис конкретної мови програмування та, можливо, об'єктно-орієнтований стиль (ланцюжок методів).

Як би виглядав цей точний «регулярний вираз» у C, наприклад? Код потрібно було б змінити.

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


0

Широко використовуються двигуни регулярної експресії, сумісні з Perl , забезпечуючи тривалий синтаксис регулярного вираження, який розуміють багато редакторів та мови. Як @ JDługosz зазначав у коментарях, Perl 6 (не просто нова версія Perl 5, але зовсім інша мова) намагався зробити регулярні вирази більш зрозумілими, будуючи їх з індивідуально визначених елементів. Наприклад, ось приклад граматики для розбору URL-адрес із Wikibooks :

grammar URL {
  rule TOP {
    <protocol>'://'<address>
  }
  token protocol {
    'http'|'https'|'ftp'|'file'
  }
  rule address {
    <subdomain>'.'<domain>'.'<tld>
  }
  ...
}

Розбиття подібного регулярного виразу дозволяє кожному біту бути визначеним індивідуально (наприклад, обмеження domainбуквено-цифровим) або розширене за допомогою підкласингу (наприклад FileURL is URL, обмеження protocolмають бути лише "file").

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

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