Действительно ли регулярны регулярные выражения? - PullRequest
17 голосов
/ 30 сентября 2008

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

  1. положить в строку
  2. Волшебное регулярное выражение
  3. Выйти строка

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

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

Ответы [ 20 ]

2 голосов
/ 30 сентября 2008

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

2 голосов
/ 30 сентября 2008

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

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

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

1 голос
/ 30 сентября 2008

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

1 голос
/ 30 сентября 2008

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

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

1 голос
/ 19 апреля 2010

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

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

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

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 или когда C # был новым). Кроме того, приведенная выше очень многословная идея даже не несовместима со «старыми» регулярными выражениями; API может быть легко реализован как тот, который создает регулярное выражение старого стиля под капотом.

0 голосов
/ 30 сентября 2008

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

0 голосов
/ 11 ноября 2008

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

Два примера 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))
0 голосов
/ 11 октября 2008

Я всегда рассматривал эту проблему как проблему стандартного блока.

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

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

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

0 голосов
/ 30 сентября 2008

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

0 голосов
/ 30 сентября 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...