Pull to refresh

Comments 45

Регекспы — это черная магия
Прикольно, что на Хабре живет черный маг :)
Регекспы — это рядовой рабочий инструмент.
Рядовой рабочий инструмент черного мага ;)
для обычных людей все программисты — черные маги, а программисты умеющие эффективно и правильно решать задачи регулярными выражениями видимо должны быть чернейшими магами =)

Вообще регулярки очень мощная и при этом довольно таки сложная для понимания штука. И шишек в них — грузовой поезд, для каждой задачи свои. И очень правильно сказано — «Используйте только те регэкспы, которые вы написали сами». Хотя есть несколько регекспов, которые можно и позаимствовать, например валидация email адреса, хотя и для этой задачи есть множество различных регулярок.

Стоит наверное еще добавить один немаловажный пункт:
«Не используйте регулярные выражения для решения простых задач, которые можно решить другими, более простыми и быстрыми средствами» или «Пользуйтесь, но без фанатизма»
Если у тебя есть проблема, и ты подумал «сейчас я ее решу с помощью регэксов» — значит, у тебя уже две проблемы :)) ©
Если есть возможность, лучше использовать генератор парсеров по EBNF или PEG грамматикам.
Но если обойтись без регэксов всё-таки нельзя, то надо хотя бы использовать правильные инструменты. Например, RegexBuddy — подсвечивает синтаксис, позволяет просмотреть структуру выражения в виде дерева. Но самое главное — там есть отладчик. Упрощает работу с регэксами на порядок, рекомендую.
Насчёт вложенности:
my $rem;
$rem = qr/ (?>[^()]+|\((??{$rem})\))*/;
$str =~ /\($rem\)/;
Мысль я думая понята. Так с помощью динамич регекспов можно решать различные проблемы вложенности :) В перле есть их поддержка, Интерестно как обстоят дела в др языках.
Вы не поняли. Регулярные выражения они на то и регулярные, что описывают регулярные языки (ну, по идее — в Perl/и др. можно распознавать и более «сложные» языки). А регулярные языки не могут выразить вложенность!

Для более сложного есть контекстно-независимые грамматики, которые удобнее для таких задач. Попробуйте написать парсер XML (или же S-выражений, что проще) на регулярках и на CFG и как говорится, почувствуйте разницу.
Не понял философию про регулярные/нерегулярные языки. Если у вам встречается рекурсивные данные, то от рекурсии не уйти, если только не задать максимальную глубину рекурсии. А в некоторых задачах глубина рекурсии данных может быть большой. В этом случае вам все равно придется рекурсивно парсить. Вопрос только чем — рекурсивными регулярками или рекурсивным кодом.

На практике в PHP очень часто использую рекурсивные регулярки (?R). Один из примеров — парсер уравнения (может быть бесконечное кол-во вложенных скобок). Среди известных примеров, библиотека DbSimple (http://dklab.ru/lib/DbSimple/), ф-ция _expandPlaceholdersFlow — осуществляет подстановку плейсхолдеров. По-моему правильно и удобно.
> Вопрос только чем — рекурсивными регулярками или рекурсивным кодом.

Парсером LL, LR или там GLR (в общем — даешь ему BNF, а он делает свое черное дело). Самое главное — *парсером*. На входе строка (или последовательность token'ов), на выходе — AST.

> На практике в PHP очень часто использую рекурсивные регулярки (?R).

И абсолютно зря. Нормальные люди описывают грамматики в BNF, а затем используют либо Yacc+Flex, либо комбинаторные парсеры.
Не уверен, что Yacc+Flex выйграет у регулярок PHP по сумме коэффициентов
время, потраченное на основение + время потраченное настройку + кроссплатформенность ;)
Еще как выиграет. Все дело в том, что именно *фундментальные ограничения* регулярных выражений и *практическая необходимость* в разборе более широкого класса грамматик, кроме всего прочего, мотивировали создание BNF и таких инструментов, как Yacc/Flex.
в komodo IDE есть отличная тулза — rx toolkit — пишешь текст, пишешь постепенно регексп и оно сразу подвесчивает что нашло. конечно такое можно и самому сообразить…

советую по регулярным выражениям почитать «регулярные выражения. 2-е изд. / Дж. Фридл. — СПб.: Питер, 2003. — 464с (ISBN 5-272-00331-4)»
Хм, не думаю, что издательство «Питер» эту книгу «освободило». Но ввиду мизерного тиража (3000 экземпляров) ничего другого не остается, кроме как скачивать из альтернативных источников :(
Последние русское издание, если не ошибаюсь выпустило издательство Слово (которые букс, ру)
Регулярные выражения, 3-е издание / Дж. Фридл. — СПб.: Символ-Плюс, 2008 (ISBN-10: 5-93286-121-5)
Тираж 2000 экз. :(
Блин, да, Символ Плюс, в мозгу чего то клинануло, букс.ру эт их лавочка :)
Лучше 3 издание, Питер 2008, Орейли 2006.
В EPIC на эклипс есть подобное, но там кнопочку надо жать :)
+ 1000 за, чтение фридела, статья спорная,

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

символ «-» не всегда указывает на диапазон (на пример если он будет в самом начале)

если говорить, что давайте писать не так «…» а вот так «…» то хорошо бы говорить почему именно, довод, «выглядит проще», «красивее» — это не правильно
Я пишу из своей практики. Если кому-то повезло с чужими выражениями, я рад за него. Но в реальности приходиться менять условия и тут придется разобрать чужой регэксп, по-любому.

Скорость работы… пишите проще, меньше шаблонов и больше конкретики — я писал об этом в статье и будут Ваши выражения быстры и верны.

Да, симовол "-" и в конце и в начале диапазона воспринимается как просто символ. Можно это использовать, главное не нарваться на описанную выше проблему. Я регулярно наблюдаю эту ошибку, поэтому решил что это важно.

Мне казалось я написал причины… но все же аргумент за простоту и красоту:
Код, имеет свойство переписываться и для меня важно быстро и безошибочно определить что он делает, поменять его, оставив простоту и ясность. Я всегда могу усложнить код, но упростить, как правило, очень сложно.
Статья полезная!
Но забыл написать про «ленивые» и «жадные» регэпсы.
Часто на них ошибки делают.
* «ленивые» и «жадные» квантификаторы
Стоит об это написать?
Думаю, что про это надо написать. Плюс стоит описать принцип работы, т.е. каким образом обрабатывается строка по регулярному выражению. Сейчас пример не вспомню, но в какой-то книге было это объяснение и в конце приведён регексп типа b*b*b*b*b*b*b*b*b*b*b*$ применительно к строке bbbbbbbbbb, ну и пояснения, что такая регулярка будет выполняться очень долго, так как будет сперва хватать всю строку, потом посимвольно откатываться назад и так для каждого символа (не квантификатора) в регулярке.
С вложенность (как раз парсинг html) строили динамеческие регэкспы, исходя из максимальной длины вложенности. Для большей части html который нам попадался (популярные интернет порталы) хватало вложенности 2-3, иногда в частных случаях 4-5 ( например тэги div вконтакте :) ).
На такой вложенности скорость работы вполне терпима, а вот альтернатива в виде посимвольный разбора строки с составлением объекта-прокси (использовали open source библиотеку на AS3), на больших страницах потребляла на порядок больше системных ресурсов.

Спасибо за статью )
немного оффтоп, по поводу IP — недавно обнаружил (что в общем не секрет, просто я как-то пропустил этот момент) что IP резолвятся как в обычном и десятичном представлении, так и в хексе и восьмеричном. То есть взяв скажем ya.ru и один из адресов 77.88.21.8, можем достучаться по нему как 1297618184, 0x4D581508 и 011526012410. Опять же, ничего нового для тех кто знает/помнит особенности IPv4, просто от парсинга IP-адреса вспомнилось.
>Опять же, поскольку по-умолчанию парсеры «жадные» то в первый шаблон...

Хотелось бы поправить. Жадные не парсеры, а квантификаторы в регулярных выражениях ;)
Спасибо за уточнение, некоторые вещи вылетают из головы когда тебя и так понимают. А термины должны быть точными.
> В таких случаях лучше делать простой фильтр на откровенно невалидный ввод ( типа SQL injection )
Вы по книгам Фленова учились?
НА SQL-inj НЕ НУЖНО проверять. Нужно просто правильно работать с данными.

Ну и дополнение: не стоит делать BB-теги на регекспах, за исключением тех случаев, когда вам не страшны XSS.
Чтобы сделать BB-коды безопасными, надо использовать алгоритм State Machine. И есть готовые реализации.
Не могу не согласиться. Вопрос в том как проверять.

PS. Без понятия кто такой Фленов :) Учился в универе. Давно. На физика.

А ещё часто народ забывает экранировать динамические части regexp-ов.
В PHP для этого есть функция php.net/preg_quote

>> Втаких случаях лучше делать простой фильтр на откровенно невалидный ввод
>> /^\d+\.\d+\.\d+\.\d+$/

Смотря откуда ip берётся, и куда. Все прекрасно помнят дырку в IPB с заголовком HTTP_CLIENT_IP…

Никогда небыло таких проблем с рэгэкспами только с буквами вконце выражения типо x,m, s всегда забывал предназначения, приходилось гуглить ;)
$_='192.168.0.1';
$ip_is_valid = do{my($r,$x)=('^(\d+)'.('\.(\d+)'x3).'$',1);for(m/$r/gx){$x&=($_>=0&&$_<=255);}$x;};
А зачем, если не секрет, используете модификатор gx?
Какой смысл в переменной $r?
тогда 999.999.999.999 и нет проблем
хотел бы заказать хабре статью про I2P
Sign up to leave a comment.

Articles