Многим программистам знакома радость быстрого создания регулярных выражений, в наши дни часто с помощью какого-либо веб-сервиса, или, более традиционно, в интерактивном режиме, или, возможно, написания небольшого сценария, в котором регулярное выражение находится в стадии разработки, и набора тестовых примеров. , В любом случае процесс является итеративным и довольно быстрым: продолжайте взламывать загадочно выглядящую строку, пока она не совпадет и не захватит то, что вы хотите, и отклонит то, что вы не хотите.
Для простого случая результат может быть примерно таким, как регулярное выражение Java:
Pattern re = Pattern.compile(
"^\\s*(?:(?:([\\d]+)\\s*:\\s*)?(?:([\\d]+)\\s*:\\s*))?([\\d]+)(?:\\s*[.,]\\s*([0-9]+))?\\s*$"
);
Многие программисты также знают, что нужно редактировать регулярное выражение или просто кодировать регулярное выражение в устаревшей базе кода. С небольшим редактированием, чтобы разбить его на части, вышеприведенное регулярное выражение все еще очень легко понять любому, кто достаточно хорошо знаком с регулярными выражениями, и ветеран регулярного выражения должен сразу увидеть, что он делает (ответьте в конце поста, если кто-то захочет выполнить упражнение сами разберемся)
Однако для того, чтобы регулярное выражение стало действительно доступным только для записи, не нужно усложнять ситуацию, и даже при тщательной документации (что, конечно, каждый делает для всех сложных регулярных выражений, которые они пишут ...), изменение регулярного выражения становится сложная задача. Это также может быть очень опасной задачей, если регулярное выражение не проходит тщательное модульное тестирование (но каждый, конечно, имеет комплексные модульные тесты для всех своих сложных регулярных выражений , как положительных, так и отрицательных ...).
Итак, вкратце, есть ли решение / альтернатива для записи-чтения для регулярных выражений, не теряя своей силы? Как будет выглядеть приведенное выше регулярное выражение с альтернативным подходом? Любой язык хорош, хотя многоязычное решение было бы лучше, в той степени, что регулярные выражения являются многоязычными.
И затем, что делает более раннее регулярное выражение, так это: анализирует строку чисел в формате 1:2:3.4
, захватывая каждое число, где пробелы разрешены и 3
требуются только .
Ответы:
Несколько человек упомянули сочинение из небольших партий, но никто еще не привел пример, так что вот мой:
Не самая читаемая, но я чувствую, что она понятнее оригинала.
Кроме того , C # имеет
@
оператор , который может предшествовать строки для того , чтобы указать , что следует понимать буквально (без экранирующих символов), так чтоnumber
было бы@"([\d]+)";
источник
[\\d]+
и[0-9]+
должно быть просто\\d+
(ну, некоторые могут найти[0-9]+
более читабельным). Я не собираюсь редактировать вопрос, но вы можете исправить этот ответ.\d
будут соответствовать любому, что считается числом, даже в других системах нумерации (китайская, арабская и т. Д.), В то время как[0-9]
будут совпадать только со стандартными цифрами. Я все же стандартизировал\\d
и учел это вoptionalDecimal
структуре.Ключом к документированию регулярного выражения является его документирование. Слишком часто люди бросают в то, что кажется шумом линии, и оставляют это на этом.
В Perl
/x
оператор в конце регулярного выражения подавляет пробелы позволяя документировать регулярное выражение.Вышеупомянутое регулярное выражение тогда станет:
Да, он немного поглощает вертикальные пробелы, хотя его можно сократить, не жертвуя слишком большой читабельностью.
Глядя на это регулярное выражение, можно увидеть, как оно работает (и не работает). В этом случае это регулярное выражение будет соответствовать строке
1
.Подобные подходы могут быть приняты на другом языке. Там работает опция python re.VERBOSE .
Perl6 (вышеприведенный пример был для perl5) развивает это с концепцией правил, которая приводит к еще более мощным структурам, чем PCRE (он обеспечивает доступ к другим грамматикам (контекстно-зависимым и контекстно-зависимым), чем просто обычные и расширенные регулярные).
В Java (откуда берется этот пример) можно использовать конкатенацию строк для формирования регулярного выражения.
По общему признанию, это создает намного больше
"
в строке, что может привести к некоторой путанице, ее легче читать (особенно с подсветкой синтаксиса в большинстве IDE) и документировать.Ключ в том, чтобы распознать силу и «написать один раз» природу, в которую часто попадают регулярные выражения Написание кода для защиты от этого, чтобы регулярное выражение оставалось ясным и понятным, является ключевым. Для ясности мы форматируем код Java - регулярные выражения ничем не отличаются, когда язык дает вам возможность сделать это.
источник
Режим многословия, предлагаемый некоторыми языками и библиотеками, является одним из ответов на эти вопросы. В этом режиме пробелы в строке регулярного выражения удаляются (так что вам нужно использовать
\s
), и комментарии возможны. Вот короткий пример в Python, который поддерживает это по умолчанию:На любом языке, который этого не делает, реализация переводчика из многословного в «нормальный» режим должна быть простой задачей. Если вы беспокоитесь о читабельности ваших регулярных выражений, вы, вероятно, вполне оправдываете это время.
источник
Каждый язык, использующий регулярные выражения, позволяет вам составлять их из более простых блоков, чтобы упростить чтение, и с помощью чего-либо более сложного, чем (или столь же сложного, как) ваш пример, вы обязательно должны воспользоваться этой опцией. Особая проблема с Java и многими другими языками состоит в том, что они не рассматривают регулярные выражения как «первоклассных» граждан, вместо этого требуя, чтобы они проникли в язык через строковые литералы. Это означает, что многие кавычки и обратные слэши не являются частью синтаксиса регулярных выражений и затрудняют чтение, а также означает, что вы не можете получить намного более читабельную информацию, чем это, без эффективного определения своего собственного мини-языка и интерпретатора.
Прототипом лучшего способа интеграции регулярных выражений был, конечно, Perl с опцией пробела и операторами регулярных кавычек. Perl 6 расширяет концепцию построения регулярных выражений от частей к рекурсивным грамматикам, так что гораздо удобнее в использовании, так что на самом деле это вообще не сравнение. Язык, возможно, пропустил лодку своевременности, но его регулярное выражение поддержки было Хорошим Материалом (тм).
источник
Мне нравится использовать Expresso: http://www.ultrapico.com/Expresso.htm
Это бесплатное приложение имеет следующие функции, которые я считаю полезными с течением времени:
Например, с регулярным выражением, которое вы только что отправили, оно будет выглядеть так:
Конечно, попробовать это стоит тысячи слов, описывающих это. Пожалуйста, обратите внимание, что я имею в виду, связанные каким-либо образом с редактором этого приложения.
источник
Для некоторых вещей это может помочь просто использовать грамматику как BNF. Это может быть намного легче читать, чем регулярные выражения. Такой инструмент, как GoldParser Builder, может затем преобразовать грамматику в синтаксический анализатор, который сделает за вас тяжелую работу.
Грамматики BNF, EBNF и т. Д. Гораздо проще читать и составлять, чем сложные регулярные выражения. ЗОЛОТО является одним из инструментов для таких вещей.
Вики-ссылка c2 ниже содержит список возможных альтернатив, которые можно найти, с некоторыми обсуждениями. По сути, это ссылка "см. Также", чтобы дополнить мою рекомендацию по грамматическому движку:
Альтернативы регулярным выражениям
источник
Это старый вопрос, и я не видел никаких упоминаний о словесных выражениях, поэтому я решил добавить эту информацию сюда и для будущих искателей. Вербальные выражения были специально разработаны, чтобы сделать регулярное выражение человеком понятным, без необходимости изучать символическое значение регулярного выражения. Смотрите следующий пример. Я думаю, что это лучше всего то, что вы просите.
Этот пример для javascript, вы можете найти эту библиотеку сейчас для многих языков программирования.
источник
Простейшим способом было бы по-прежнему использовать регулярные выражения, но построить свое выражение из составления более простых выражений с описательными именами, например, http://www.martinfowler.com/bliki/ComposedRegex.html (и да, это из строки concat)
однако в качестве альтернативы вы также можете использовать библиотеку комбинатора парсера, например, http://jparsec.codehaus.org/, которая даст вам полный рекурсивный приличный парсер. опять же, настоящая сила здесь заключается в композиции (на этот раз в функциональной композиции).
источник
Я подумал, что стоит упомянуть logstash в ГРКАХ выражения. Grok основывается на идее составления длинных выражений парсинга из более коротких. Это позволяет удобно тестировать эти строительные блоки и поставляется в комплекте с более чем 100 часто используемыми шаблонами . Помимо этих шаблонов, он позволяет использовать весь синтаксис регулярных выражений.
Вышеуказанный шаблон, выраженный в grok: (Я тестировал в приложении отладчика, но мог ошибиться):
Необязательные части и пробелы делают его немного уродливее обычного, но и здесь, и в других случаях использование grok может сделать вашу жизнь намного приятнее.
источник
В F # у вас есть модуль FsVerbalExpressions . Он позволяет вам составлять регулярные выражения из словесных выражений, а также имеет несколько готовых регулярных выражений (например, URL).
Одним из примеров этого синтаксиса является следующее:
Если вы не знакомы с синтаксисом F #, groupName - это строка «GroupNumber».
Затем они создают словесное выражение (VerbEx), которое они конструируют как «COD (? <GroupNumber> [0-9] {3}) END». Что они затем проверяют на строке «COD123END», где они получают именованную группу захвата «GroupNumber». Это приводит к 123.
Я, честно говоря, считаю, что нормальное регулярное выражение гораздо легче понять.
источник
Во-первых, поймите, что просто работающий код - это плохой код. Хороший код также должен точно сообщать о любых обнаруженных ошибках.
Например, если вы пишете функцию для перевода денег со счета одного пользователя на счет другого пользователя; вы не просто вернете логическое значение «сработало или не сработало», потому что это не дает вызывающей стороне никакого представления о том, что пошло не так, и не позволяет вызывающей стороне должным образом информировать пользователя. Вместо этого у вас может быть набор кодов ошибок (или набор исключений): не удалось найти целевой аккаунт, недостаточно средств на исходном счете, отказано в доступе, невозможно подключиться к базе данных, слишком большая загрузка (повторите попытку позже) и т. Д. ,
Теперь подумайте о своем примере «разбора строки чисел в формате 1: 2: 3.4». Все, что делает регулярное выражение - это сообщает "пройти / не пройти", что не позволяет пользователю предоставить адекватную обратную связь (независимо от того, является ли эта обратная связь сообщением об ошибке в журнале, или интерактивным графическим интерфейсом, где ошибки отображаются красным цветом как пользовательские типы или что-то еще). Какие типы ошибок он не может описать должным образом? Плохой символ в первом числе, слишком большое первое число, пропущенное двоеточие после первого числа и т. Д.
Чтобы преобразовать «плохой код, который просто работает», в «хороший код, который обеспечивает адекватно описательные ошибки», вы должны разбить регулярное выражение на множество меньших регулярных выражений (обычно это настолько малые регулярные выражения, что проще сделать это без регулярных выражений в первую очередь). ).
Делать код читаемым / обслуживаемым - это просто случайное следствие того, что код будет хорошим.
источник
:
? Представьте себе компилятор, у которого было только одно сообщение об ошибке («ОШИБКА»), который был слишком глуп, чтобы сообщить пользователю, в чем проблема. Теперь представьте тысячи веб-сайтов, которые так же глупы и отображают (например) «Плохой адрес электронной почты» и ничего более.