Есть популярная цитата Джейми Завински :
Некоторые люди, сталкиваясь с проблемой, думают: «Я знаю, я буду использовать регулярные выражения». Теперь у них две проблемы.
Как эта цитата должна быть понята?
Есть популярная цитата Джейми Завински :
Некоторые люди, сталкиваясь с проблемой, думают: «Я знаю, я буду использовать регулярные выражения». Теперь у них две проблемы.
Как эта цитата должна быть понята?
Ответы:
Некоторые технологии программирования, как правило, недостаточно понятны программистам ( регулярные выражения , числа с плавающей запятой , Perl , AWK , IoC ... и другие ).
Это могут быть удивительно мощные инструменты для решения правильного набора проблем. В частности, регулярные выражения очень полезны для сопоставления регулярных языков. И в этом суть проблемы: мало кто знает, как описать обычный язык (это часть теории информатики / лингвистики, которая использует забавные символы - вы можете прочитать об этом в иерархии Хомского ).
При работе с этими вещами, если вы используете их неправильно, маловероятно, что вы действительно решили свою первоначальную проблему. Использование регулярных выражений для соответствия HTML (далеко слишком распространенное явление) будет означать , что вы будете пропустить крайние случаи. И теперь у вас все еще есть исходная проблема, которую вы не решили, и еще одна тонкая ошибка, возникающая при использовании неправильного решения.
Это не означает, что регулярные выражения не следует использовать, а нужно работать, чтобы понять, что такое набор проблем, которые они могут решить, и не могут решить, и использовать их разумно.
Ключом к поддержке программного обеспечения является написание поддерживаемого кода. Использование регулярных выражений может противоречить этой цели. При работе с регулярными выражениями вы написали мини-компьютер (в частности, недетерминированный конечный автомат ) на специальном доменном языке. Легко написать эквивалент «Привет, мир» на этом языке и получить элементарную уверенность в нем, но дальнейшее развитие событий должно быть ограничено пониманием обычного языка, чтобы избежать написания дополнительных ошибок, которые очень сложно идентифицировать и исправить (потому что они не являются частью программы, в которой находится регулярное выражение).
Итак, теперь у вас есть новая проблема; Вы выбрали инструмент регулярного выражения для его решения (когда это неуместно), и теперь у вас есть две ошибки, которые труднее найти, потому что они скрыты в другом уровне абстракции.
Регулярные выражения - особенно нетривиальные - потенциально сложно кодировать, понимать и поддерживать. Вам нужно только взглянуть на количество вопросов в тегах «Переполнение стека», в которых респондент [regex]
предположил, что ответом на их проблему является регулярное выражение и впоследствии застрял. Во многих случаях проблема может (и, возможно, должна) быть решена другим способом.
Это означает, что если вы решили использовать регулярное выражение, у вас теперь есть две проблемы:
По сути, я думаю, что он означает, что вы должны использовать регулярные выражения, только если нет другого способа решения вашей проблемы. Другое решение, вероятно, будет легче кодировать, поддерживать и поддерживать. Это может быть медленнее или менее эффективно, но если это не так важно, простота обслуживания и поддержки должна быть главной заботой.
В основном это шутливая шутка, хотя и с долей правды.
Есть некоторые задачи, для которых регулярные выражения отлично подходят. Однажды я заменил 500 строк написанного вручную кода синтаксического анализатора рекурсивного спуска одним регулярным выражением, для полной отладки которого потребовалось около 10 минут. Люди говорят, что регулярные выражения сложно понять и отладить, но подходящие для применения не так сложны для отладки, как огромный анализатор, разработанный вручную. В моем примере потребовалось две недели, чтобы отладить все крайние случаи решения без регулярных выражений.
Однако, перефразируя дядю Бена:
С большой выразительностью приходит большая ответственность.
Другими словами, регулярные выражения добавляют выразительность вашему языку, но это возлагает большую ответственность на программиста, выбирающего наиболее читаемый способ выражения для данной задачи.
Некоторые вещи изначально выглядят как хорошая задача для регулярных выражений, но это не так. Например, что-нибудь с вложенными токенами, например HTML. Иногда люди используют регулярные выражения, когда более простой метод более понятен. Например, string.endsWith("ing")
это легче понять, чем эквивалентное регулярное выражение. Иногда люди пытаются втиснуть большую проблему в одно регулярное выражение, где более уместно разбить ее на части. Иногда люди не могут создать подходящие абстракции, повторяя регулярные выражения снова и снова вместо создания хорошо названной функции для выполнения той же работы (возможно, реализованной внутри с помощью регулярного выражения).
По какой-то причине регулярные выражения имеют странную тенденцию создавать слепую зону для нормальных принципов разработки программного обеспечения, таких как единая ответственность и DRY. Вот почему даже люди, которые их любят, иногда находят их проблемными.
Джефф Этвуд (Jeff Atwood) приводит другую интерпретацию в сообщении блога, в котором обсуждается эта цитата: « Регулярные выражения: теперь у вас две проблемы» (спасибо Euphoric за ссылку)
Анализируя полный текст постов Джейми в оригинальной ветке 1997 года, мы находим следующее:
Природа Perl поощряет использование регулярных выражений почти исключая все другие методы; они, безусловно, самый «очевидный» (по крайней мере, для людей, которые не знают ничего лучшего) способ добраться из пункта А в пункт Б.
Первая цитата слишком бойкая, чтобы воспринимать ее всерьез. Но с этим я полностью согласен. Вот что Джейми пытался сделать: не то, чтобы регулярные выражения были злом, как таковое, а чрезмерное использование регулярных выражений - зло.
Даже если вы действительно в полной мере понять регулярные выражения, вы бежите в The Golden Hammer проблемы, пытаясь решить проблему с регулярными выражениями, когда это было бы проще и понятнее , чтобы сделать то же самое с регулярным кодом (смотри также CodingHorror: Regex использование против злоупотребления Регексом ).
Есть еще одно сообщение в блоге, которое рассматривает контекст цитаты и более подробно, чем Этвуд: блог Джеффри Фридла: источник знаменитой цитаты «Теперь у вас две проблемы»
С этой цитатой происходит несколько вещей.
Цитата является повторением более раннего анекдота:
Всякий раз, когда сталкиваются с проблемой, некоторые люди говорят: «Давайте использовать AWK». Теперь у них есть две проблемы. - Д. Тилбрук
Это шутка и настоящее копание, но это также способ выделить регулярное выражение как плохое решение, связав его с другими плохими решениями. Это здорово, ха-ха, только серьезный момент.
Для меня - заметьте, эта цитата преднамеренно открыта для толкования - смысл прямой. Простое объявление идеи использования регулярного выражения не решило проблему. Кроме того, вы увеличили когнитивную сложность кода, добавив дополнительный язык с правилами, которые стоят отдельно от того, какой язык вы используете.
Несмотря на смешную шутку, вам нужно сравнить сложность решения без регулярных выражений со сложностью решения регулярных выражений + дополнительную сложность включения регулярных выражений. Возможно, стоит решить проблему с регулярным выражением, несмотря на дополнительные затраты на добавление регулярных выражений.
RegularExpressionsarenoworsetoreadormaintainthananyotherunformattedcontent; indeedaregexisprobablyeasiertoreadthanthispieceoftexthere-butunfortunatelytheyhaveabadreputationbecausesomeimplementationsdon'tallowformattingandpeopleingeneraldon'tknowthatyoucandoit.
(Регулярные выражения не хуже для чтения или поддержки, чем для любого другого неформатированного контента; действительно, регулярное выражение, вероятно, легче читать, чем этот фрагмент текста здесь - но, к сожалению, у них плохая репутация, потому что некоторые реализации не позволяют форматирование и люди в целом не знаю, что ты можешь сделать это.)
Вот тривиальный пример:
^(?:[^,]*+,){21}[^,]*+$
Что на самом деле не так сложно читать или поддерживать, но еще проще, когда это выглядит так:
(?x) # enables comments, so this whole block can be used in a regex.
^ # start of string
(?: # start non-capturing group
[^,]*+ # as many non-commas as possible, but none required
, # a comma
) # end non-capturing group
{21} # 21 of previous entity (i.e. the group)
[^,]*+ # as many non-commas as possible, but none required
$ # end of string
Это немного чрезмерный пример (комментирование $
сродни комментированию i++
), но ясно, что не должно быть проблем с чтением, пониманием и поддержанием этого.
Пока вы четко понимаете, когда подходят регулярные выражения и когда они являются плохой идеей, в них нет ничего плохого, и в большинстве случаев цитата JWZ действительно не применяется.
*+
? Как это отличается (функционально) от просто *
?
*+
в этом случае; все привязано и может быть сопоставлено за один проход автоматом, который может рассчитывать до 22. Правильный модификатор на этих наборах без запятой просто старый *
. (Более того, здесь также не должно быть различий между жадными и не жадными алгоритмами сопоставления. Это чрезвычайно простой случай.)
В дополнение к ответу ChrisF о том, что регулярные выражения «сложно кодировать, понимать и поддерживать», есть еще одно: они достаточно мощные, чтобы обмануть людей, пытаясь использовать их для анализа того, что они не могут, например HTML. Посмотрите многочисленные вопросы по SO на тему "Как мне разобрать HTML?" Например, самый эпичный ответ во всех SO!
Регулярные выражения очень мощные, но у них есть одна маленькая и одна большая проблема; их трудно написать, и почти невозможно прочитать.
В лучшем случае использование регулярного выражения решает проблему, поэтому у вас есть только проблема обслуживания сложного кода. Если вы не совсем правильно понимаете регулярное выражение, у вас есть как исходная проблема, так и проблема с нечитаемым кодом, который не работает.
Иногда регулярные выражения называют кодом только для записи. Столкнувшись с регулярным выражением, которое требует исправления, часто быстрее начать с нуля, чем пытаться понять выражение.
Проблема в том, что регулярное выражение - сложный зверь, и вы решите свою проблему только в том случае, если будете использовать регулярное выражение. Если вы этого не сделаете, вы столкнетесь с двумя проблемами: ваша исходная проблема и регулярное выражение.
Вы утверждаете, что он может выполнять работу с сотнями строк кода, но вы также можете утверждать, что 100 строк ясного и краткого кода лучше, чем одна строка регулярного выражения.
Если вам нужно какое-то доказательство этого: вы можете проверить этот SO Classic или просто прочесать тег SO Regex.
Значение имеет две части:
Как вы просите об этом в 2014 году, было бы интересно сосредоточиться на идеологиях языков программирования контекста 1997 года по сравнению с сегодняшним контекстом. Я не буду вступать в эту дискуссию здесь, но мнения о Perl и самом Perl сильно изменились.
Тем не менее, чтобы остаться в контексте 2013 года ( de l'eau a coulé sous les ponts depuis), я бы посоветовал сосредоточиться на реконструкции в цитатах, используя известный комикс XKCD, который является прямой цитатой из фильма Джейми Завински :
Во- первых у меня были проблемы , чтобы понять этот комикс , потому что это была ссылка на Завински цитатой, и цитата из Джей-Z тексты песен, и ссылка ГНУ program --help -z
флаг 2 , так, что это было слишком много культуры для меня , чтобы понять это.
Я знал, что это было весело, я чувствовал это, но я действительно не знал, почему. Люди часто шутят по поводу Perl и регулярных выражений, тем более, что это не самый хиппикий язык программирования, на самом деле не знаю, почему он должен быть веселым ... Может быть, потому что Perl-монгеры делают глупости .
Таким образом, первоначальная цитата кажется саркастической шуткой, основанной на реальных проблемах (боль?), Вызванных программированием с помощью инструментов, которые причиняют боль. Точно так же, как молоток может повредить масону, программируя с помощью инструментов, которые разработчик не выбрал бы, если бы мог причинить вред (мозг, чувства). Иногда возникают большие споры о том, какой инструмент является лучшим, но он почти бесполезен, потому что это проблема вашего вкуса или вкуса вашей команды программистов , культурных или экономических причин. Еще один отличный комикс XKCD об этом:
Я могу понять людей, испытывающих боль от регулярных выражений, и они верят, что другой инструмент лучше подходит для того, для чего предназначены регулярные выражения. Когда @ karl-bielefeldt отвечает на ваш вопрос с большой выразительностью, приходит большая ответственность , и регулярные выражения особенно обеспокоены этим. Если разработчик не заботится о том, как он обращается с регулярными выражениями, это в конечном итоге станет проблемой для людей, которые будут поддерживать код позже.
Я закончу с этим ответом о воссоздании цитат цитатой, показывающей типичный пример из Perl Best Practices Дамиана Конви (книга 2005 года).
Он объясняет, что пишет шаблон так:
m{'[^\\']*(?:\\.[^\\']*)*'}
... не более приемлемо, чем писать такую программу :
sub'x{local$_=pop;sub'_{$_>=$_[0
]?$_[1]:$"}_(1,'*')._(5,'-')._(4
,'*').$/._(6,'|').($_>9?'X':$_>8
?'/':$")._(8,'|').$/._(2,'*')._(
7,'-')._(3,'*').$/}print$/x($=).
x(10)x(++$x/10).x($x%10)while<>;
Но это может быть переписано , это все еще не симпатично, но по крайней мере это теперь выживаемо.
# Match a single-quoted string efficiently...
m{ ' # an opening single quote
[^\\']* # any non-special chars (i.e., not backslash or single quote)
(?: # then all of...`
\\ . # any explicitly backslashed char
[^\\']* # followed by any non-special chars
)* # ...repeated zero or more times
' # a closing single quote
}x
Этот вид кода прямоугольной формы является второй проблемой, а не регулярными выражениями, которые могут быть отформатированы понятным, понятным и читаемым способом.
/* Multiply the first 10 values in an array by 2. */ for (int i = 0 /* the loop counter */; i < 10 /* continue while it is less than 10 */; ++i /* and increment it by 1 in each iteration */) { array[i] *= 2; /* double the i-th element in the array */ }
Если есть что-то, чему вы должны научиться у информатики, это иерархия Хомского . Я бы сказал, что все проблемы с регулярными выражениями возникают из-за попыток синтаксического анализа контекстной грамматики. Когда вы можете наложить ограничение (или думаете, что можете наложить ограничение) на уровни вложенности в CFG, вы получите эти длинные и сложные регулярные выражения.
Регулярные выражения больше подходят для токенизации, чем для полномасштабного анализа.
Но удивительно большой набор вещей, которые нужно анализировать программистам, может быть проанализирован обычным языком (или, что еще хуже, почти разбирается обычным языком, и если вы пишете немного больше кода ...).
Поэтому, если кто-то привык «ага, мне нужно разбирать текст на части, я буду использовать регулярное выражение», то легко пойти по этому пути, когда вам нужно что-то, что ближе к автомату с нажатием, парсеру CFG или еще более мощные грамматики. Это обычно заканчивается слезами.
Итак, я думаю, что цитата - это не столько кричащие регулярные выражения, они имеют свое применение (и они хорошо используются, они действительно очень полезны), но чрезмерная зависимость от регулярных выражений (или, в частности, некритический их выбор) ,
JWZ просто сошел с ума от этой цитаты. регулярные выражения ничем не отличаются от любой языковой функции - их легко испортить, сложно использовать элегантно, иногда мощно, иногда неуместно, часто хорошо документировано, часто полезно.
То же самое можно сказать и для арифметики с плавающей запятой, замыканий, ориентации на объекты, асинхронного ввода-вывода или чего-либо еще, что вы можете назвать. Если вы не знаете, что делаете, языки программирования могут огорчить вас.
если вы думаете, что регулярные выражения трудно читать, попробуйте прочитать эквивалентную реализацию синтаксического анализатора для использования рассматриваемого шаблона. часто выигрывают регулярные выражения, потому что они более компактны, чем полноценные парсеры ... и в большинстве языков они также быстрее.
не откладывайте использование регулярных выражений (или любой другой языковой функции), потому что саморекламируемый блоггер делает неквалифицированные заявления. Попробуйте сами и посмотрите, что работает для вас.
Мой любимый подробный ответ на этот вопрос дает знаменитый Роб Пайк в блоге, воспроизведенном из внутреннего комментария кода Google: http://commandcenter.blogspot.ch/2011/08/regular-expressions-in-lexing- and.html
В итоге, дело не в том, что они плохие , а в том, что они часто используются для задач, для которых они не обязательно подходят, особенно когда речь идет о лексизировании и анализе некоторого ввода.
Регулярные выражения сложно написать, сложно написать хорошо и они могут быть дорогостоящими по сравнению с другими технологиями ... С другой стороны, лексеры довольно легко написать правильно (если не так компактно), и их очень легко протестировать. Попробуйте найти буквенно-цифровые идентификаторы. Не так сложно написать регулярное выражение (что-то вроде «[a-ZA-Z _] [a-ZA-Z_0-9] *»), но на самом деле не так сложно написать простой цикл. Производительность цикла, тем не менее, будет намного выше и будет включать гораздо меньше кода под прикрытием. Библиотека регулярных выражений - большая вещь. Использование одного для разбора идентификаторов похоже на использование Ferrari для покупки молока.
Он говорит гораздо больше, утверждая, что регулярные выражения полезны, например, для одноразового сопоставления шаблонов в текстовых редакторах, но редко должны использоваться в скомпилированном коде и т. Д. Это стоит прочитать.
Это связано с эпиграммой Алана Перлиса № 34:
Строка является строгой структурой данных, и везде, где она передается, происходит многократное дублирование процесса. Это идеальное средство для сокрытия информации.
Поэтому, если вы выбираете символьную строку в качестве структуры данных (и, естественно, код на основе регулярных выражений в качестве алгоритмов для ее манипулирования), у вас возникает проблема, даже если она работает: плохой дизайн вокруг неправильного представления данных, которое трудно распространяться и неэффективно.
Однако часто это не работает: исходная проблема не решена, и поэтому в этом случае у вас есть две проблемы.
Регулярные выражения широко используются для быстрого и грязного анализа текста. Они являются отличным инструментом для выражения шаблонов, которые немного сложнее простого сопоставления строк.
Однако по мере того, как регулярные выражения становятся более сложными, некоторые вопросы поднимают голову.
Таким образом, слишком легко начать с задачи обработки текста, применить к ней регулярные выражения и в итоге получить две проблемы: исходную проблему, которую вы пытались решить, и работу с регулярными выражениями, которые пытаются решить (но не решают правильно) оригинальная проблема.