Подтвердить что ты не робот

Почему регулярные выражения настолько противоречивы?

При изучении регулярных выражений (иначе известных как RegEx-es) существует много людей, которые, похоже, видят регулярные выражения как Святой Грааль. Что-то, что выглядит так сложно - просто должен быть ответ на любой вопрос. Они склонны считать, что каждая проблема разрешима с использованием регулярных выражений.

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

Почему регулярные выражения считаются настолько противоречивыми? Есть ли распространенные недоразумения в отношении того, как они работают? Или может быть широкое убеждение, что регулярные выражения, как правило, медленные?

4b9b3361

Ответ 1

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

Ответ 2

Предоставление регулярных выражений

Значительное продвижение к демистификации шаблонов, ранее называемых "регулярными выражениями", - это Perls /x флаг регулярных выражений - иногда написанный (?x) при вставке - это позволяет пропустить пробел (разрыв строки, отступы) и комментарии. Это серьезно улучшает читаемость и, следовательно, ремонтопригодность. Белое пространство позволяет использовать когнитивные фрагменты, поэтому вы можете видеть, какие группы с чем.

Современные шаблоны теперь также поддерживают как относительно пронумерованные, так и названные обратные ссылки. Это означает, что вам больше не нужно подсчитывать группы захвата, чтобы выяснить, что вам нужно $4 или \7. Это помогает при создании шаблонов, которые могут быть включены в дополнительные шаблоны.

Вот пример относительно пронумерованной группы захвата:

$dupword = qr{ \b (?: ( \w+ ) (?: \s+ \g{-1} )+ ) \b }xi;
$quoted  = qr{ ( ["'] ) $dupword  \1 }x;

И вот пример превосходного подхода именованных захватов:

$dupword = qr{ \b (?: (?<word> \w+ ) (?: \s+ \k<word> )+ ) \b }xi;
$quoted  = qr{ (?<quote> ["'] ) $dupword  \g{quote} }x;

Грамматические представления

Лучше всего, эти именованные записи могут быть помещены в блок (?(DEFINE)...), чтобы вы могли отделить объявление от выполнения отдельных именованных элементов ваших шаблонов. Это заставляет их действовать скорее как подпрограммы внутри шаблона.
 Хороший пример такого "грамматического регулярного выражения" можно найти в этом ответе и этот. Они больше похожи на грамматическую декларацию.

Как последнее напоминает:

... убедитесь, что никогда не записываете шаблоны линейного шума. Тебе не нужно, и ты не должен. Нельзя поддерживать язык программирования, который запрещает использование пробелов, комментариев, подпрограмм или буквенно-цифровых идентификаторов. Поэтому используйте все эти вещи в своих шаблонах.

Это нельзя переоценить. Конечно, если вы не используете эти вещи в своих шаблонах, вы часто создадите кошмар. Но если вы сделаете, их не нужно.

Вот еще один пример современной грамматической схемы, для анализа RFC 5322:   используйте 5.10.0;

$rfc5322 = qr{

   (?(DEFINE)

     (?<address>         (?&mailbox) | (?&group))
     (?<mailbox>         (?&name_addr) | (?&addr_spec))
     (?<name_addr>       (?&display_name)? (?&angle_addr))
     (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
     (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ; (?&CFWS)?)
     (?<display_name>    (?&phrase))
     (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

     (?<addr_spec>       (?&local_part) \@ (?&domain))
     (?<local_part>      (?&dot_atom) | (?&quoted_string))
     (?<domain>          (?&dot_atom) | (?&domain_literal))
     (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                   \] (?&CFWS)?)
     (?<dcontent>        (?&dtext) | (?&quoted_pair))
     (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

     (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
     (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
     (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
     (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

     (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
     (?<quoted_pair>     \\ (?&text))

     (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
     (?<qcontent>        (?&qtext) | (?&quoted_pair))
     (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                          (?&FWS)? (?&DQUOTE) (?&CFWS)?)

     (?<word>            (?&atom) | (?&quoted_string))
     (?<phrase>          (?&word)+)

     # Folding white space
     (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
     (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
     (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
     (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
     (?<CFWS>            (?: (?&FWS)? (?&comment))*
                         (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

     # No whitespace control
     (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

     (?<ALPHA>           [A-Za-z])
     (?<DIGIT>           [0-9])
     (?<CRLF>            \x0d \x0a)
     (?<DQUOTE>          ")
     (?<WSP>             [\x20\x09])
   )

   (?&address)

}x;

Разве это не замечательно - и великолепно? Вы можете взять грамматику в стиле BNF и перевести ее прямо в код, не теряя своей фундаментальной структуры!

Если современные грамматические шаблоны по-прежнему достаточно для вас, то блестящий модуль Regexp::Grammars Damian Conways предлагает более чистый синтаксис с превосходной отладкой, слишком. Вот такой же код для разбора RFC 5322 в шаблон из этого модуля:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use Data::Dumper "Dumper";

my $rfc5322 = do {
    use Regexp::Grammars;    # ...the magic is lexically scoped
    qr{

    # Keep the big stick handy, just in case...
    # <debug:on>

    # Match this...
    <address>

    # As defined by these...
    <token: address>         <mailbox> | <group>
    <token: mailbox>         <name_addr> | <addr_spec>
    <token: name_addr>       <display_name>? <angle_addr>
    <token: angle_addr>      <CFWS>? \< <addr_spec> \> <CFWS>?
    <token: group>           <display_name> : (?:<mailbox_list> | <CFWS>)? ; <CFWS>?
    <token: display_name>    <phrase>
    <token: mailbox_list>    <[mailbox]> ** (,)

    <token: addr_spec>       <local_part> \@ <domain>
    <token: local_part>      <dot_atom> | <quoted_string>
    <token: domain>          <dot_atom> | <domain_literal>
    <token: domain_literal>  <CFWS>? \[ (?: <FWS>? <[dcontent]>)* <FWS>?

    <token: dcontent>        <dtext> | <quoted_pair>
    <token: dtext>           <.NO_WS_CTL> | [\x21-\x5a\x5e-\x7e]

    <token: atext>           <.ALPHA> | <.DIGIT> | [!#\$%&'*+-/=?^_`{|}~]
    <token: atom>            <.CFWS>? <.atext>+ <.CFWS>?
    <token: dot_atom>        <.CFWS>? <.dot_atom_text> <.CFWS>?
    <token: dot_atom>        <.CFWS>? <.dot_atom_text> <.CFWS>?
    <token: dot_atom_text>   <.atext>+ (?: \. <.atext>+)*

    <token: text>            [\x01-\x09\x0b\x0c\x0e-\x7f]
    <token: quoted_pair>     \\ <.text>

    <token: qtext>           <.NO_WS_CTL> | [\x21\x23-\x5b\x5d-\x7e]
    <token: qcontent>        <.qtext> | <.quoted_pair>
    <token: quoted_string>   <.CFWS>? <.DQUOTE> (?:<.FWS>? <.qcontent>)*
                             <.FWS>? <.DQUOTE> <.CFWS>?

    <token: word>            <.atom> | <.quoted_string>
    <token: phrase>          <.word>+

    # Folding white space
    <token: FWS>             (?: <.WSP>* <.CRLF>)? <.WSP>+
    <token: ctext>           <.NO_WS_CTL> | [\x21-\x27\x2a-\x5b\x5d-\x7e]
    <token: ccontent>        <.ctext> | <.quoted_pair> | <.comment>
    <token: comment>         \( (?: <.FWS>? <.ccontent>)* <.FWS>? \)
    <token: CFWS>            (?: <.FWS>? <.comment>)*
                             (?: (?:<.FWS>? <.comment>) | <.FWS>)

    # No whitespace control
    <token: NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f]

    <token: ALPHA>           [A-Za-z]
    <token: DIGIT>           [0-9]
    <token: CRLF>            \x0d \x0a
    <token: DQUOTE>          "
    <token: WSP>             [\x20\x09]

    }x;

};


while (my $input = <>) {
    if ($input =~ $rfc5322) {
        say Dumper \%/;       # ...the parse tree of any successful match
                              # appears in this punctuation variable
    }
}

Theres много хорошего в perlre manpage, но эти резкие улучшения в основных конструктивных особенностях регулярного выражения никоим образом не ограничиваются Perl в одиночестве. Действительно, справочная страница pcrepattern может быть проще читать и охватывает ту же территорию.

Современные шаблоны почти не имеют ничего общего с примитивными вещами, которые вы преподавали в своем конечном классе автоматов.

Ответ 3

Regexes - отличный инструмент, но люди думают: "Эй, какой отличный инструмент, я буду использовать его, чтобы сделать X!" где X - это то, что лучше для другого инструмента (обычно это синтаксический анализатор). Это стандарт с использованием молотка, где вам нужна проблема с отверткой.

Ответ 4

Почти каждый, кто знает, кто регулярно использует регулярные выражения (каламбур), исходит из фона Unix-ish, где они используют инструменты, которые рассматривают REs как первоклассные конструкторы программирования, такие как grep, sed, awk и Perl. Поскольку для использования регулярного выражения почти нет синтаксических накладных расходов, их производительность идет вверх, когда они это делают.

Напротив, программисты, которые используют языки, в которых RE являются внешней библиотекой, обычно не учитывают, какие регулярные выражения могут принести в таблицу. Программист "временная стоимость" настолько высок, что: а) REs никогда не появлялись как часть их обучения, или б) они не "думают" с точки зрения RE и предпочитают возвращаться к более привычным шаблонам.

Ответ 5

Регулярные выражения позволяют записывать конечный конечный автомат (FSM) компактным способом, обрабатывая строку ввода. Существует по крайней мере две причины, почему использование регулярных выражений сложно:

  • Разработка программного обеспечения в старой школе включает в себя множество планов, бумажных моделей и тщательную мысль. Регулярные выражения хорошо вписываются в эту модель, потому что для правильного написания эффективного выражения требуется много внимания, визуализируя пути FSM.

    Современные разработчики программного обеспечения гораздо лучше выработают код и используют отладчик для выполнения его выполнения, чтобы убедиться, что код правильный. Регулярные выражения не очень хорошо поддерживают этот рабочий стиль. Один "запуск" регулярного выражения - это, фактически, атомная операция. Трудно наблюдать пошаговое выполнение в отладчике.

  • Слишком легко написать регулярное выражение, которое случайно принимает больше ввода, чем вы предполагаете. Значение регулярного выражения на самом деле не соответствует допустимому вводу, оно не соответствует недопустимому вводу. Методы "отрицательных тестов" для регулярных выражений не очень продвинуты или, по крайней мере, широко не используются.

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

Если сегодня существует проблема с использованием регулярных выражений среди разработчиков программного обеспечения, я думаю, что это связано главным образом с этими двумя факторами.

Ответ 6

Люди склонны думать, что регулярные выражения сложны; но это потому, что они используют их неправильно. Написание сложных однострочных номеров без комментариев, отступов или названий. (Вы не втискиваете свое сложное выражение SQL в одну строку, без комментариев, отступов или псевдонимов, не так ли?). Так что да, для многих людей они не имеют смысла.

Однако, если ваша работа имеет какое-либо отношение к анализу текста (примерно любое веб-приложение там...), и вы не знаете регулярного выражения, вы сосать на свою работу, и вы тратите свое время и вашего работодателя. Есть отличные ресурсы, чтобы научить вас всему, что вам когда-либо понадобится, и многое другое.

Ответ 7

Потому что им не хватает самого популярного инструмента обучения в общепринятых IDE: Нет мастера регулярных выражений. Даже автозаполнение. Вы должны все это прописать самостоятельно.

Ответ 9

Я не думаю, что они такие противоречивые.

Я также думаю, что вы ответили на свой вопрос, потому что вы указываете, как глупо было бы использовать их везде (Не все является обычным язык 2) или вообще не использовать их. Вы, программист, должны принять разумное решение о том, когда регулярные выражения помогут коду или повредит его. Когда сталкиваются с таким решением, две важные вещи, которые следует иметь в виду, - это ремонтопригодность (что подразумевает читаемость) и расширяемость.

Для тех, кто особенно против них, я предполагаю, что они никогда не научились правильно их использовать. Я думаю, что большинство людей, которые проводят всего несколько часов с приличным учебным пособием, будут выяснять их и быстро говорить. Здесь мое предложение о том, с чего начать:

http://docs.python.org/howto/regex

Хотя эта страница говорит о регулярных выражениях в контексте Python, я нашел, что информация очень применима в другом месте. Есть несколько вещей, которые специфичны для Python, но я считаю, что они четко обозначены и легко запоминаются.

Ответ 10

Регулярные выражения относятся к строкам, какие арифметические операторы относятся к числам, и я бы не счел их спорными. Я думаю, что даже довольно мужественный активист OO, как я (кто бы предпочел выбирать другие объекты по строкам), было бы трудно отказаться от них.

Ответ 11

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

Хороший программист должен знать, где их использовать, а где нет. Типичным примером является синтаксический анализ нерегулярных языков (см. Определение регулярности языка).

Я думаю, что вы не ошибетесь, если сначала ограничитесь реальными регулярными выражениями (без расширений). Некоторые расширения могут сделать вашу жизнь немного легче, но если вы найдете что-то трудно выразить как реальное регулярное выражение, это может быть признаком того, что регулярное выражение не является правильным инструментом.

Ответ 12

Вы почти можете также спросить, почему goto противоречивы.

В принципе, когда вы получаете так много "очевидной" власти, люди склонны злоупотреблять ими в ситуациях, когда они не являются лучшим вариантом. Например, количество людей, которые просят разбор CSV или XML или HTML в регулярных выражениях, меня поражает. Это неправильный инструмент для работы. Но некоторые пользователи все равно настаивают на использовании регулярных выражений.

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

Обратите внимание, что регулярные выражения все еще могут использоваться для анализа CSV, XML, HTML и т.д. Но обычно это не в одном регулярном выражении.

Ответ 13

Я не думаю, что "спорным" является правильное слово.

Но я видел множество примеров, в которых люди говорят: "Какое регулярное выражение мне нужно сделать для такого-то и такого манипулирования строкой?" которые являются проблемами X-Y.

Другими словами, они исходили из предположения, что регулярное выражение - это то, что им нужно, но им было бы лучше с помощью split(), такого как perl tr///, где символы заменяются одним другой или просто индекс().

Ответ 14

Это интересный предмет.
Многие поклонники регулярных выражений, похоже, сбивают с толку краткость формулы с эффективностью.
Кроме того, регулярное выражение, требующее много размышлений, дает своему автору огромное удовлетворение, которое делает его законным сразу.

Но... регулярные выражения поэтому удобны, когда производительность не является проблемой, и вам нужно быстро работать с текстовым выходом, например, в Perl. Кроме того, хотя производительность есть проблема, вы можете не пытаться бить библиотеку regexp с помощью самодельного алгоритма, который может быть глючным или менее эффективным.

Кроме того, существует ряд причин, по которым regexps подвергаются несправедливой критике, например

  • regexp неэффективен, потому что создание верхнего не очевидно.
  • некоторые программисты "забывают" компилировать только один раз, когда регулярное выражение используется много раз (например, статический шаблон в Java).
  • некоторые программисты идут на пробную и ошибочную стратегию - работают еще меньше с регулярными выражениями!

Ответ 15

Я думаю, что Learning Regex и поддержка регулярного выражения делает непопулярным, большинство разработчиков ленивы, или большинство из них полагаются на внешние библиотеки, чтобы сделать для них синтаксический анализ... они полагаются на Google для ответа и даже спрашивают на форумах полный код для своей проблемы. Но когда приходит реализация или изменение/поддержание регулярного выражения, они просто терпят неудачу.

Существует популярное высказывание "Друзья не позволяют друзьям использовать Regex для анализа HTML"

Но, насколько мне известно, я создал полные HTML-парсеры, использующие Regex, и я нахожу себя в том, что регулярное выражение лучше анализирует строки html как по скорости, так и по памяти (если у вас есть идея, что вам нужно:))

Ответ 16

Регулярные выражения - серьезная тайна для многих людей, включая меня. Он отлично работает, но это похоже на математическое уравнение. Я рад сообщить, что кто-то наконец создал консолидированное расположение различных функций регулярного выражения в http://regexlib.com/. Теперь, если Microsoft создаст только класс регулярных выражений, который автоматически выполнит большую часть обычных вещей, таких как удаление писем или фильтрация дат.

Ответ 17

Получить RegexBuddy. Тогда вы будете бросать регулярные выражения вокруг, как профессионал, и как бонус! вы начинаете понимать их!

Ответ 18

Я нахожу регулярные выражения неоценимыми. Когда мне нужно делать некоторые "нечеткие" поиски и, возможно, заменяется. Когда данные могут меняться и иметь определенную случайность. Однако, когда мне нужно сделать простой поиск и заменить, или проверить строку, я не использую регулярные выражения. Хотя я знаю многих людей, которые это делают, они используют его для всего. Это противоречие.

Если вы хотите надеть клей в стене, не используйте молоток. Да, это сработает, но к тому моменту, когда вы получите молот, я смогу положить 20 стенок в стену.

Регулярные выражения должны использоваться для того, для чего они предназначены, и не что иное.

Ответ 19

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

Ответ 20

В некоторых случаях я думаю, что вам нужно их использовать. Например, для создания лексера.

По-моему, это точка зрения людей, которые могут писать regexp и людей, которые этого не делают (или вряд ли). Я лично считаю, что это хороший пример, например, для корректного ввода формы, будь то в javascript для предупреждения пользователя или на серверном языке.

Ответ 21

Я думаю, что это менее известный метод среди программистов. Таким образом, для этого нет широкого признания. И если у вас есть нетехнический менеджер для просмотра вашего кода или просмотра вашей работы, регулярное выражение очень плохое. Вы будете часами писать идеальное регулярное выражение, и вы получите несколько оценок для модуля, думая, что он написал так мало строк кода. Кроме того, как сказано в другом месте, чтение регулярных выражений - очень сложная задача.

Ответ 22

Достойные системы регулярных выражений, такие как используемые в lex и yacc для определения компилятора, хороши, очень полезны и чисты. В этих системах типы выражений определяются в терминах других. Это отвратительные искаженные нелинейные линейные шумовые гигантские однострочные регулярные выражения, обычно встречающиеся в perl и sed code (и т.д.), Которые являются "противоречивыми" (мусор).

Ответ 23

Лучшее допустимое и нормальное использование регулярного выражения для проверки формата адреса электронной почты.

Это хорошее применение.

Я использовал регулярные выражения бесчисленное количество раз, как одноразовые в TextPad, для массажа плоских файлов, создания файлов csv, создания операторов вставки SQL и т.д.

Хорошо написанные регулярные выражения не должны быть слишком медленными. Обычно альтернативы, такие как тонны звонков на Replace, намного медленнее. Возможно также сделать это за один проход.

Многие ситуации требуют ровно регулярных выражений и ничего больше.

Замена специальных непечатаемых символов безобидными символами - еще одно хорошее использование.

Я могу, конечно, представить себе, что существуют некоторые кодовые базы, которые злоупотребляют регулярными выражениями в ущерб ремонтопригодности. Я этого никогда не видел. Я действительно был отброшен разработчиками кода для того, чтобы не использовать регулярные выражения.