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

Являются ли регулярные выражения реально поддерживаемыми?

Любой код, который я видел, который использует Regexes, имеет тенденцию использовать их как черный ящик:

  • Вставить строку
  • Магическое Regex
  • Получить строку

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

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

4b9b3361

Ответ 1

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

Множество реализаций регулярных выражений позволяет вам создавать регулярные выражения с пробелами и комментариями.
См. http://www.regular-expressions.info/comments.html
и Coding Horror: Регулярные выражения: теперь у вас есть две проблемы

Любой код, который я видел, который использует Regexes, имеет тенденцию использовать их как черный ящик:

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

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

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

Изменить: пожалуйста, также прочитайте комментарий Джеффа к этому ответу о производственном коде.

Ответ 2

Обязательно.

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

Ответ 3

Я не знаю, какой язык вы используете, но Perl - например - поддерживает флаг x, поэтому пробелы игнорируются в регулярных выражениях, если они не экранированы, поэтому вы можете разбить его на несколько строк и прокомментировать все inline:

$foo =~ m{
    (some-thing)          # matches something
    \s*                   # matches any amount of spaces
    (match another thing) # matches something else
}x;

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

Ответ 4

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

Ответ 5

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

Замените регулярное выражение на "C" или "С#" или "Java" или "Python" или "Perl" или "SQL" или "Ruby" или "awk" или... что угодно, и вы получите то же самое вопрос.

Regex - это еще один язык, кодированный Хаффманом, чтобы быть эффективным при сопоставлении строк. Так же, как Java, Perl, PHP или особенно SQL, у каждого языка есть свои сильные и слабые стороны, и вам нужно знать язык, на котором вы пишете, когда вы его пишете (или поддерживаете), чтобы иметь какую-либо надежду на то, чтобы быть продуктивным.

Изменить: Майк, регулярное выражение - это Хаффман, закодированный в том, что общие вещи, которые нужно сделать, короче, чем более редкие вещи. Буквенные совпадения текста обычно представляют собой один символ (тот, который вы хотите сопоставить). Существуют специальные символы - общие короткие. Специальные конструкции, такие как (?:), длиннее. Это не то же самое, что было бы распространено в общедоступных языках, таких как Perl, С++ и т.д., Поэтому кодировка Хаффмана была нацелена на эту специализацию.

Ответ 6

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

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

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

Ответ 7

Regex не является единственным способом сделать что-то. Логически можно сделать код, который может иметь регулярное выражение. Регулярные выражения просто

  • Fast
  • Проверено и проверено
  • Мощное

Ответ 8

RegExs может быть очень поддерживаемым, если вы используете новые функции, введенные Perl 5.10. К функциям, которые я имею в виду, относятся функции back-ported от Perl 6.

Пример скопирован непосредственно из perlretut.

Определение названных шаблонов

Некоторые регулярные выражения используют одинаковые подшаблоны в нескольких местах. Начиная с Perl 5.10, можно определить именованные подшаблоны в разделе шаблона, чтобы их можно было вызвать по имени в любом месте шаблона. Этот синтаксический шаблон для этой группы определения (?(DEFINE)(?<name>pattern)...). Вставка именованного шаблона записывается как (?&name).

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

/^
  (?&osg)\ * ( (?&int)(?&dec)? | (?&dec) )
        (?: [eE](?&osg)(?&int) )?
 $
 (?(DEFINE)
     (?<osg>[-+]?)         # optional sign
     (?<int>\d++)          # integer
     (?<dec>\.(?&int))     # decimal fraction
 )
/x

Ответ 9

известная цитата о регулярных выражениях:

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

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

Ответ 10

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

Ответ 11

Являются ли regexes способ сделать что-то? Это зависит от задачи.

Как и во всем программировании, нет трудного и быстрого права или неправильного ответа.

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

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

Ответ 12

Есть много возможностей сделать RegEx более удобным. В конце концов, это просто метод (хороший?) Программист должен узнать, когда дело доходит до крупных (или иногда даже незначительных) изменений. Когда не было действительно хороших профессионалов, никто бы не стал их беспокоить из-за их сложного синтаксиса. Но они быстры, компактны и очень гибки в выполнении своей работы.

Для .NET-пользователей может быть Linq to RegEx "библиотека хуже выглядит или" Читаемая библиотека регулярных выражений". Это делает их более удобными в обслуживании и, тем не менее, легче писать. Я использовал оба из них в собственных проектах, я знал, что код html-source, который я проанализировал с ними, может меняться в любое время.

Но поверьте мне: когда вы хлопаете по ним, они могут даже высмеять, чтобы писать и читать.:)

Ответ 13

У меня есть политика тщательного комментирования нетривиальных регулярных выражений. Это означает описание и обоснование каждого атома, который не соответствует самому себе. Некоторые языки (Python, для одного) предлагают "подробные" регулярные выражения, которые игнорируют пробелы и позволяют комментировать; используйте это, когда это возможно. В противном случае, перейдите атом через атом в комментарии над регулярным выражением.

Ответ 14

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

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

Ответ 15

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

Некоторые люди уже упомянули флаг "x" в Perl, который немного помогает, но не много.

Мне нравятся регулярные выражения, но не синтаксис. Было бы неплохо иметь возможность создавать регулярное выражение из читаемых, значимых имен методов. Например, вместо этого кода С#:

foreach (var match in Regex.Matches(input, @"-?(?<number>\d+)"))
{
    Console.WriteLine(match.Groups["number"].Value);
}

у вас может быть что-то гораздо более подробное, но более читаемое и поддерживаемое:

int number = 0;
Regex r = Regex.Char('-').Optional().Then(
    Regex.Digit().OneOrMore().Capture(c => number = int.Parse(c))
);
foreach (var match in r.Matches(input))
{
    Console.WriteLine(number);
}

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

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

instead of:   -?(?<number>\d+)
could have:   ("-" or "") + (number = digit * [1..])

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

Я действительно не знаю, почему существует столько возражений против переосмысления синтаксиса для регулярных выражений, даже когда переработаны целые языки программирования (например, Perl 6 или когда С# был новым). Кроме того, вышеупомянутая очень многословная идея даже несовместима с "старыми" регулярными выражениями; API может быть легко реализован как тот, который строит регулярное выражение старого стиля под капотом.

Ответ 16

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

Ответ 17

Regex определен как "язык программирования только для записи". Однако я не думаю, что это означает, что вы должны избегать их. Я просто думаю, что вы должны прокомментировать ад из их намерений. Я обычно не большой поклонник комментариев, которые объясняют, что делает строка, я могу прочитать код для этого, но Regexs являются исключением. Прокомментируйте все!

Ответ 18

Я обычно перехожу в область написания файла спецификации сканера. Сканер или "генератор сканера" - это, по сути, оптимизированный синтаксический анализатор текста. Поскольку я обычно работаю с Java, моим предпочтительным методом является JFlex (http://www.jflex.de), но есть также Lex, YACC и несколько других.

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

Когда дело доходит до кода, у меня есть файл спецификации, содержащий всю логику синтаксического анализа. Я запускаю его через инструмент генератора сканера по выбору для генерации исходного кода на выбранном языке. Затем я просто переношу все это в функцию парсера или класс. Эта абстракция позволяет легко управлять всей логикой регулярных выражений, и это очень хорошая производительность. Конечно, это слишком сложно, если вы работаете только с одним или двумя регулярными выражениями, и вам требуется как минимум 2-3 дня, чтобы узнать, что происходит, но если вы когда-нибудь работаете, скажем, с 5 или 6 или 30 из них, это становится действительно приятной особенностью, и реализация логики синтаксического анализа начинается только за минуты, и они остаются легкими в обслуживании и легко документируются.

Ответ 19

Я всегда сталкивался с этой проблемой как проблема с блочным блоком.

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

Например, чтобы соответствовать URI, у вас есть протокол, полномочия, субдомен, домен, tld, путь, аргументы (по крайней мере). И некоторые из них являются необязательными!

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

Ответ 20

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

Два примера PHP PCRE (особенности или конкретное использование не важны):

1)
  $dktpat = '/^[^a-z0-9]*'. // skip any initial non-digits
    '([a-z0-9]:)?'. // division within the district
    '(\d+)'. // year
    '((-)|-?([a-z][a-z])-?)'. // type of court if any - cv, bk, etc.
    '(\d+)'. // docket sequence number
    '[^0-9]*$/i'; // ignore anything after the sequence number
  if (preg_match($dktpat,$DocketID,$m)) {

2)
    $pat= array (
      'Row'        => '\s*(\d*)',
      'Parties'    => '(.*)',
      'CourtID'    => '<a[^>]*>([a-z]*)</a>',
      'CaseNo'     => '<a[^>]*>([a-z0-9:\-]*)</a>',
      'FirstFiled' => '([0-9\/]*)',
      'NOS'        => '(\d*)',
      'CaseClosed' => '([0-9\/]*)',
      'CaseTitle'  => '(.*)',
    );
    // wrap terms in table syntax
    $pat = '#<tr>(<td[^>]*>'.
      implode('</td>)(</tr><tr>)?(<td[^>]*>',$pat).
      '</td>)</tr>#iUx';
    if (preg_match_all ($pat,$this->DocketText,$matches, PREG_PATTERN_ORDER))