Когда вам НЕ следует использовать регулярные выражения? [закрыто]

50

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

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

Но есть ли другие области, в которых нет регулярных выражений?


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

C69
источник
9
Разбор HTML с помощью regexp - это не просто «известная дорога к многочисленным ошибкам». Это на самом деле невозможно .
Kramii Восстановите Монику
19
Мало того, что это невозможно, это также приводит к безумию и вечному проклятию
Мартин Уикман,
3
@ Jörg: Regexp - это просто сокращение от регулярного выражения.
Joren
3
@ Jörg: Очень верно, что существует огромная разница между регулярными выражениями в математике и их реализациями в программных библиотеках. Также верно, что большинство библиотек регулярных выражений имеют расширения, которые выходят далеко за рамки восприятия просто регулярных языков, и что называть их регулярными выражениями не всегда так уместно. Я согласен с вами, что есть две разные концепции. Но у них одно и то же имя; регулярное выражение по-прежнему просто аббревиатура, а не сам по себе термин. На этом сайте множество примеров использования полного термина для библиотек программного обеспечения.
Джорен
2
@ Йорг - это семантика. Хотя может быть хорошей идеей называть эти шаблоны разными именами (хотя бы для того, чтобы избежать ошибки «регулярные выражения для регулярных языков»), «регулярные выражения» / «регулярные выражения» не очень хорошая попытка и приводит только к дополнительная путаница.
Коби

Ответы:

60

Не используйте регулярные выражения:

  • Когда есть парсеры.

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

Не пытайтесь, например, анализировать исходный код C # . Вместо этого проанализируйте его, чтобы получить значимую древовидную структуру или токены.

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

Что если вам нужно искать букву, как маленькую, так и заглавную? Если вы любите регулярные выражения, вы будете их использовать. Но не проще ли / быстрее / удобочитаемее использовать два поиска, один за другим? Скорее всего, в большинстве языков вы достигнете лучшей производительности и сделаете свой код более читабельным.

Например, пример кода в ответе Ingo является хорошим примером, когда вы не должны использовать регулярные выражения. Просто поищи foo, потом по bar.

  • При разборе человека пишу.

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

  • При проверке некоторых типов данных.

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

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

  • Когда ваш код будет прочитан. А потом читайте снова, и снова и снова, каждый раз разными разработчиками.

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

Арсений Мурзенко
источник
9
«Серьезно, если я возьму твой код и должен его просмотреть или изменить, я не хочу тратить неделю на то, чтобы понять последовательность символов длиной в двадцать строк». +1!
funkybro
1
Это гораздо лучший ответ, чем его сводная сестра по переполнению стека: stackoverflow.com/questions/7553722/…
Коби,
1
Если вы используете Perl / PCRE (и, возможно, другие современные разновидности регулярных выражений), прочитайте о подпрограммах, именованных группах захвата и (?(DEFINE))утверждениях;) Вы можете писать очень чистые регулярные выражения, используя их, и фактически, когда вы используете те, вы будете писать грамматики, которые очень похоже на то, что вы написали бы в yacc или в
другом подобии
2
Использование регулярных выражений для анализа слов из черного списка является ошибкой.
Дэн Рэй
В мире нет причин избегать использования регулярных выражений в подобной строке "<a href='foo'>stuff</a>". Современные регулярные выражения не имеют проблем с этим.
2012 года
18

Самое главное: когда вы анализируете язык, это не обычный язык .

HTML это не обычный язык и разбор его с регулярным выражением является не возможно (не только трудно или дорога к багги кода).

Matteo
источник
4
Неправильно! Если вы используете любую из современных разновидностей регулярных выражений (Perl, PCRE, Java, .NET, ...), вы можете выполнять рекурсию и утверждения и, таким образом, анализировать также сопоставление контекстно-зависимых и контекстно-зависимых грамматик.
NikiC
9
@NikiC. Не неправильно. «Современные разновидности регулярных выражений» не являются регулярными выражениями (которые могут использоваться для разбора обычных языков, отсюда и название). Я согласен, что с PRE вы можете делать больше, но я бы не назвал их просто «регулярными выражениями» (как в оригинальном вопросе).
Маттео
1
Современные регулярные выражения настолько далеко от того, чему учила ваша бабушка, что регулярные выражения могли бы сделать это, если ее совет не имеет значения. И даже примитивные регулярные выражения могут обрабатывать большинство маленьких фрагментов HTML. Этот общий запрет нелеп и нереален. Регексы были созданы для такого рода вещей. И да, я знаю, о чем говорю .
2012 года
12

В stackoverflow часто можно увидеть, как люди спрашивают регулярные выражения, чтобы выяснить, содержит ли данная строка то или иное. Это, ИМХО, изменение цели регулярного выражения. Даже если решение существует (с использованием негативных утверждений за кадром или тому подобного), часто гораздо лучше использовать регулярное выражение для того, для чего оно было сделано, и обрабатывать отрицательный случай с помощью программной логики.

Пример:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}
Инго
источник
1
+1: Несколько раз я избегал загонять себя в угол с помощью регулярных выражений, останавливаясь и спрашивая себя: «Хорошо, что я специально пытаюсь сопоставить?» а не "Чего я пытаюсь избежать?"
5

Два случая:

Когда есть более простой способ

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

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

Когда регулярные выражения недостаточно сильны

  • Если вам нужен парсер, используйте парсер.
Kramii Восстановить Монику
источник
0

Регулярные выражения не могут идентифицировать рекурсивные структуры . Это фундаментальное ограничение.

Возьмите JSON - это довольно простой формат, но поскольку объект может содержать другие объекты в качестве значений элементов (произвольно глубоких), синтаксис является рекурсивным и не может быть проанализирован с помощью регулярного выражения. С другой стороны, CSV может быть проанализирован с помощью регулярных выражений, поскольку он не содержит никаких рекурсивных структур.

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

Обратите внимание, что это не имеет ничего общего с тем, насколько сложным или запутанным является формат. S-выражения действительно очень просты, но не могут быть проанализированы с помощью регулярного выражения. CSS2, с другой стороны, является довольно сложным языком, но не содержит рекурсивных структур и поэтому может быть проанализирован с помощью регулярного выражения. (Хотя это не так для CSS3 из-за выражений CSS, которые имеют рекурсивный синтаксис.)

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

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

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

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

JacquesB
источник