Комментарии 86
Ну это классика, кто сказал не помню:
«Если у вас есть проблема, и вы решили с ней разобраться с помощью регэкспов, то теперь у вас две проблемы».
«Если у вас есть проблема, и вы решили с ней разобраться с помощью регэкспов, то теперь у вас две проблемы».
+71
про источник: regex.info/blog/2006-09-15/247
+2
Я люблю регулярные выражения. Будучи однажды написанными, они обретают собственный разум. Иногда они даже разговаривают со мной.
+50
Будучи однажды написанными, они становятся не понятными через неделю :)
+10
начать им отвечать — фатальная ошибка программиста
+3
Единожды осилив и влившись в регекспы уже не сможешь себе отказать в удовольствии накропать 30-40 символов визуальной белиберды ;-) Ясное дело для простых задач это нонсенс.
+16
Я не знаю деталей, но вряд ли уж сразу машину Тьюринга. Логичнее было бы подняться на один уровень вверх и получить контекстно-свободные языки (автоматы с очередями).
+3
Надо подумать… вы наверно правы относительно "(?1)". А про Тьюринга прокатит только с "(??{...})"… Спасибо. Задумался.
+4
Кажется, контекстно-свободный язык тоже не получить. en.wikipedia.org/wiki/Regular_expression#Patterns_for_non-regular_languages
Хотя я тоже не уверен в деталях, regex-ами с памятью особо не пользовался.
Хотя я тоже не уверен в деталях, regex-ами с памятью особо не пользовался.
0
Ну и регулярные выражения регулярным выражениям рознь. Их в общем-то несколько диалектов.
Начиная от POSIX и заканчивая Perl.
Начиная от POSIX и заканчивая Perl.
+2
:)
-2
farm2.static.flickr.com/1372/1128067974_9985a11078.jpg
0
А вот первоисточник: www.xkcd.com/208/
+3
Меня лично в регулярных выражения раздражает от факт, что Oracle их поддерживает не полностью и как-то через одно место.
-4
Гм. А может быть вас лично в Oracle раздражает тот факт, что регулярные выражения он поддерживает не полностью и как-то через одно место? Задумайтесь :)
+17
вот он, результат анти-регулярного мышления! :)
0
В подобных случаях я обычно вспоминаю анекдот:
Всплывает бегемот. На носу у него сидит лягушка. Она оглядывается и говорит:
— Чувствую же, что-то плавать мешает. И точно — бегемот к жопе прилип!
С одной стороны, умозаключение лягушки абсурдно. А с другой, это результат здорового эгоизма (ну может быть чуток слишком здоровенного :) ). Каждый человек в какой-то мере — центр собственной вселенной. И это естественно, а значит — не безобразно :) Если не злоупотреблять.
Иногда надо напоминать немного забывшимся (и себе, в т.ч.), что, мол, «ты не пуп земли». Но напоминать мягко. Ибо пусть бросит в меня минус тот, кто сам без греха :)
Понятно ведь, что для trak Oracle гораздо ближе к центру его вселенной, чем какие-то регэкспы. Я лишь хотел обратить его внимание на тот факт, что существуют другие системы координат :)
Всплывает бегемот. На носу у него сидит лягушка. Она оглядывается и говорит:
— Чувствую же, что-то плавать мешает. И точно — бегемот к жопе прилип!
С одной стороны, умозаключение лягушки абсурдно. А с другой, это результат здорового эгоизма (ну может быть чуток слишком здоровенного :) ). Каждый человек в какой-то мере — центр собственной вселенной. И это естественно, а значит — не безобразно :) Если не злоупотреблять.
Иногда надо напоминать немного забывшимся (и себе, в т.ч.), что, мол, «ты не пуп земли». Но напоминать мягко. Ибо пусть бросит в меня минус тот, кто сам без греха :)
Понятно ведь, что для trak Oracle гораздо ближе к центру его вселенной, чем какие-то регэкспы. Я лишь хотел обратить его внимание на тот факт, что существуют другие системы координат :)
+1
>panic: regfree data code 'Ъ' during global destruction.
Perl — ТруЪ
Perl — ТруЪ
+2
>panic: regfree data code 'Ъ' during global destruction
Perl — труЪ язык:))
Perl — труЪ язык:))
+2
И все же совсем без них тоже грустно. Я вот, как С++ разработчик, очень жду следующую сишку (ну, которая, с++0х или как там её) в том числе из-за встроенных регепсов. (Я знаю про сторонние библиотеки и «можно ж самому написать» — но это не тоже самое, что native-поддержка фичи).
+1
Я думаю в некоторых случаях простой перебор строки будет работать намного быстрее чем регулярное выражение в C++. (Это заметно только при многократном использовании, например при написании парсера, который парсит огромное кол-во информации, проверено на своем опыте).
P.S. Но поддержка регепсов еще никому не вредила.
P.S. Но поддержка регепсов еще никому не вредила.
+1
> Теперь программист не может быть уверен, что его «регулярное выражение» будет
> использовать конечный объём памяти. Или не зациклится.
Нижеприведённый исходник будет использовать конечное количество памяти и не зациклится.
Хоть в нём используется и не только регэксп, но программист применяя их всё ещё может быть уверенным в вышеперечисленных требованиях решая задачу подобную этой со скобками.
#!/usr/bin/perl
my $s1=«qwe(sdfs{asdfasdF)asdf}asd»;
my $s2=«asdf(cxzf{gtrrt}asdf)rewasdfasd»;
our %braces=(
'\(' => '\)',
'\{' => '\}',
'\[' => '\]',
'\',
);
our $brm=join('',keys(%braces),values(%braces));
sub checkBraces
{
my $s=shift;
my $found=1;
while($found)
{
$found=0;
while(my($l,$r)=each(%braces))
{
while($s=~s/$l[^$brm]*$r//)
{
$found=1;
}
}
}
if($s=~m/([$brm])/o){print «false! $1 in $s\n»; return 0;} else {print «OK!\n»; return 1;}
}
checkBraces($s1);
checkBraces($s2);
> использовать конечный объём памяти. Или не зациклится.
Нижеприведённый исходник будет использовать конечное количество памяти и не зациклится.
Хоть в нём используется и не только регэксп, но программист применяя их всё ещё может быть уверенным в вышеперечисленных требованиях решая задачу подобную этой со скобками.
#!/usr/bin/perl
my $s1=«qwe(sdfs{asdfasdF)asdf}asd»;
my $s2=«asdf(cxzf{gtrrt}asdf)rewasdfasd»;
our %braces=(
'\(' => '\)',
'\{' => '\}',
'\[' => '\]',
'\',
);
our $brm=join('',keys(%braces),values(%braces));
sub checkBraces
{
my $s=shift;
my $found=1;
while($found)
{
$found=0;
while(my($l,$r)=each(%braces))
{
while($s=~s/$l[^$brm]*$r//)
{
$found=1;
}
}
}
if($s=~m/([$brm])/o){print «false! $1 in $s\n»; return 0;} else {print «OK!\n»; return 1;}
}
checkBraces($s1);
checkBraces($s2);
-1
Подобный пример показывает как не нужно решать эту задачу. Во-первых его довольно сложно читать, во вторых вычислительная сложность как минимум на степень больше чем нужно.
Естественый способ решения задачи на императивном языке — использовать стек. Работает за линейное время и память от количества символов в строке.
При этом будет достаточно всего одного прохода через каждый символ строки — один простой цикл.
В нем нужно все открывающие скобки ложить в стек, а когда встречается закрывающая — пробовать достать из стека соответствующую открывающую, если не получается значит скобки расставлены неправильно.
Естественый способ решения задачи на императивном языке — использовать стек. Работает за линейное время и память от количества символов в строке.
При этом будет достаточно всего одного прохода через каждый символ строки — один простой цикл.
В нем нужно все открывающие скобки ложить в стек, а когда встречается закрывающая — пробовать достать из стека соответствующую открывающую, если не получается значит скобки расставлены неправильно.
+8
Если уж использовать циклы и не думать про производительность, то: $_=$s1; tr/()[]{}//cd;1 while s/\(\)|\[]|{}//g; print /^$/;
0
«Года четыре назад, я был на собеседовании в одной крупной компании»…
я тут пару месяцев назад был на собеседовании, где попросили написать строковый калькулятор с использование регулярных выражений…
сейчас активно «тренируюсь» с регуляркой, парся логи и сайты, но правда не с Перлом
в общем спасибо, было интересно
я тут пару месяцев назад был на собеседовании, где попросили написать строковый калькулятор с использование регулярных выражений…
сейчас активно «тренируюсь» с регуляркой, парся логи и сайты, но правда не с Перлом
в общем спасибо, было интересно
0
У Вас все оба из описанных заблуждений — какая-то крайность. Никогда так не думал о регекспах.
+5
Собеседование было вообще унылым чуть-более,-чем-полностью, но окончательно меня добил вопрос: «Напишите регулярное выражение, проверяющее правильность расстановки скобок.» (То есть отсутствие ситуаций "{<}>".)
Регулярка, о которой вас спрашивали, должна выглядеть как-то так:
\( ( ( (?>[^()]+) | (?R) )* ) \)
тут описан рекурсивный случай для круглых скобок.
+4
Расскажите за что минус.
+2
А объяснить как оно работает? :)
0
Я сейчас на семинаре, поэтому кратенько.
(?R) — это и есть рекурсия, в этом месте как бы подставляется ещё раз весь шаблон целиком
(?>[^()]+) | — это условия прекращения рекурсии, означает «впереди не встречаются скобки».
Т.е. рекурси идёт в себя, пока не кончаются скобки. Остальное, вроде, не надо объяснять?
(?R) — это и есть рекурсия, в этом месте как бы подставляется ещё раз весь шаблон целиком
(?>[^()]+) | — это условия прекращения рекурсии, означает «впереди не встречаются скобки».
Т.е. рекурси идёт в себя, пока не кончаются скобки. Остальное, вроде, не надо объяснять?
0
НЛО прилетело и опубликовало эту надпись здесь
Скажите, я один такой, кому достаточно просто написать регэксп (ну допустим парсер-выдиралка определенных данных из html), но сходу сложно понять что делает чужой?
+7
Я молчу про решения типа:
очевидно оно менее эффективно, чем сравнение с пустой строкой:
Вообще то:
Результат:
Поясняю: проверка пустым регулярным выражением работает быстрее
по поводу второго лирического отступления:
— как часто в работе вам приходилось проверять наличие 10 букв 'а' в след за которыми идут 10 любых символов?
— да неочень часто честно говоря…
— как часто вы ищете слово или фразу в строке или тексте?
— частенько
Поэтому в языке python чаще у вас будет встречаться «оптимальное не самое красивое и удобное решение»
Вообще тут рассматриваються проблемы «говнокода» и почему-то в этом сразу стал виноват язык Perl.
Никто же не кричит особо что язык PHP или visual basic говно, только потому что там много говнокода (там низкий порог вхождения и действительно много говнокода).
В говнокоде виноваты программисты, а не язык программирования.
В Perl действительно очень удобно работать с регулярными выражениями, но это не значит что пользоваться ими надо везде где только можно. И если у кого-то что-то не получаеться, это не значит что рег-экспы надо выкинуть на помойку, это очень удобный и сильный инструмент в руках опытного человека.
if (/./) { print "not empty\n"; }
очевидно оно менее эффективно, чем сравнение с пустой строкой:
if ($_ ne "") { print "not empty\n"; }
Вообще то:
use strict;
use Benchmark qw(:all);
my $a='a'x100;
cmpthese(1_000_000, {
'regex' => sub { if ($a !~//) { my $b = 'b' x 100; }; },
'noregex' => sub { if ($a ne "") { my $b = 'b' x 100; }; },
});
Результат:
(warning: too few iterations for a reliable count) Rate noregex regex noregex 2500000/s -- -20% regex 3125000/s 25% --
Поясняю: проверка пустым регулярным выражением работает быстрее
по поводу второго лирического отступления:
— как часто в работе вам приходилось проверять наличие 10 букв 'а' в след за которыми идут 10 любых символов?
— да неочень часто честно говоря…
— как часто вы ищете слово или фразу в строке или тексте?
— частенько
Поэтому в языке python чаще у вас будет встречаться «оптимальное не самое красивое и удобное решение»
Вообще тут рассматриваються проблемы «говнокода» и почему-то в этом сразу стал виноват язык Perl.
Никто же не кричит особо что язык PHP или visual basic говно, только потому что там много говнокода (там низкий порог вхождения и действительно много говнокода).
В говнокоде виноваты программисты, а не язык программирования.
В Perl действительно очень удобно работать с регулярными выражениями, но это не значит что пользоваться ими надо везде где только можно. И если у кого-то что-то не получаеться, это не значит что рег-экспы надо выкинуть на помойку, это очень удобный и сильный инструмент в руках опытного человека.
+13
if ($a !~//) — не удовлетворяет никакой строке. Может быть, вы имели в виду /^$/ (а точнее, /\A\z/)?
+4
Да, вы правы, поторопился я.
В этой части автор прав, ибо с выражением /^$/ регулярные выражения отрабатывают медленее ( /\A\z/ ещё дольше обрабатывается).
Но, всё равно это не true-Perl-way и им, я думаю, мало кто пользуется, ибо можно использовать более простую конструкцию:
TMTOWTDI =)
В этой части автор прав, ибо с выражением /^$/ регулярные выражения отрабатывают медленее ( /\A\z/ ещё дольше обрабатывается).
Но, всё равно это не true-Perl-way и им, я думаю, мало кто пользуется, ибо можно использовать более простую конструкцию:
if ($a) { print 'non empty'; }
TMTOWTDI =)
+1
>>Заданный вопрос сродни вопросу: «Какова сумма углов треугольника, если его стороны равны 1, 2 и 50 сантиметров». Он выдаёт полное незнание предмета.
Сумма углов треугольника разве не всегда 180 градусов?
Сумма углов треугольника разве не всегда 180 градусов?
+3
ну… если человек считает, что у треугольника могут быть такие стороны, то не известно, что он думает про углы :-)
я как раз хотел привести пример безумного вопроса :-)
я как раз хотел привести пример безумного вопроса :-)
+7
Не всегда. Она 180 градусов только на плоскости.
0
Только если он есть.
0
В циклах регулярные выражения надо использовать или с модификатором o, или выносить их выше в qr//. Я не оправдываю такое использование, как у вас в примере, а просто, к слову.
+1
В данном случае это не очень важно. Выражение работает на много медленней, чем компилится
my $a='a'x8000; cmpthese(1000, { 'regex' => sub { $a=~/a{10}.{10}$/; }, 'regex-o' => sub { $a=~/a{10}.{10}$/o; }, 'noregex' => sub { substr($a, -20, 10) eq "aaaaaaaaaa"; }, });выдаёт
regex-o 428/s -- -0% -100% regex 430/s 0% -- -100% noregex 999999999999999872/s 233593749999999968% 232812499999999968% --
0
Насколько я помню, модификатор «о» пригодится только если у Вас регулярка зависит от переменных. Если же она такая, как у автора, то соберется один раз в любом случае.
0
всё, что можно не гемороясь решить без регекспов лучше решать без регекспов
+2
Конечно, при миллионе итераций эффект замедления от регулярных выражений заметен, но на практике таких циклов не бывает, бывает чтение из базы и обработка — а это доли процента на регекспы от общего времени.
Что читается лучше — substr($a, -20, 10) eq «aaaaaaaaaa»; или $a=~/a{10}.{10}$/;? Наверно, последнее, значит и при отладке, и при поддержке займёт меньше времени и работать будет надёжней.
Что читается лучше — substr($a, -20, 10) eq «aaaaaaaaaa»; или $a=~/a{10}.{10}$/;? Наверно, последнее, значит и при отладке, и при поддержке займёт меньше времени и работать будет надёжней.
+1
Регулярное выражение описывает конечный автомат. Если вам требуется проконтролировать бесконечное количество скобок, то конечный автомат вам не поможет.
Ну-ну. Скажите еще что
/a+b/
сможет проконтролировать только конечное число символов «a», потому что де автомат конечный. (нет, в реальности бесконечностей не бывает, но там причины немного другие — ресурсы)Конечный автомат все-таки характеризуется конечным числом состояний, а не объемом информации на входе.
0
оно не запаминает количество знаков «а».
напишите регексп который матчит строки вида «aabb», «aaaabbbb»,… то есть сколько-то-а+столько-же-b?
такое выражение у вас не получится (без рекурсии) потому, что оно должно считать и помнить количество знако «а», а не факт присутствия одного-или-более «а».
напишите регексп который матчит строки вида «aabb», «aaaabbbb»,… то есть сколько-то-а+столько-же-b?
такое выражение у вас не получится (без рекурсии) потому, что оно должно считать и помнить количество знако «а», а не факт присутствия одного-или-более «а».
0
У Вас как-то внимание сакцентировано на противопоставлении «конечный-бесконечный», что истинные причины такой невозможности неочевидны. Вложенные скобочные выражения — нерегулярный язык, и описать его настоящими регулярными выражениями нельзя — я бы написал примерно так, но воля Ваша.
0
Дело в том, что доказательство нерегулярности языка «вложенные скобочки» упирается в конечность количества состояний автомата. Ведь для запоминания любой текущей глубины вложений нужно одно состояние, а глубина вложений бесконечна, следовательно конечный автомат не подходит.
А в вашей версии, факт нерегулярности языка «вложенные скобочки» неочевиден.
Как-то так.
А в вашей версии, факт нерегулярности языка «вложенные скобочки» неочевиден.
Как-то так.
0
Можно по-разному доказывать, например, опираясь на определения:
0
ч0ртов хабр!
en.wikipedia.org/wiki/Regular_grammar
en.wikipedia.org/wiki/Context-free_grammar
Правила вложенных скобок — это правила контекстно-свободной грамматики.
В статье все-таки это никак не объяснено. Неспециалиста в формальных грамматиках (меня, например) это может ввести в заблуждение.
en.wikipedia.org/wiki/Regular_grammar
en.wikipedia.org/wiki/Context-free_grammar
Правила вложенных скобок — это правила контекстно-свободной грамматики.
В статье все-таки это никак не объяснено. Неспециалиста в формальных грамматиках (меня, например) это может ввести в заблуждение.
0
Хорошо, не надо бесконечности. Напишите такой регексп для строк не дилнее 80 символов :-)
0
Не искушайте :)
Хороший пример задачи которую богопротивно решать регэкспами.
/^ab|a{2}b{2}|a{3}b{3}|a{4}b{4}|a{5}b{5}|a{6}b{6}|a{7}b{7}|a{8}b{8}|a{9}b{9}|a{10}b{10}|
a{11}b{11}|a{12}b{12}|a{13}b{13}|a{14}b{14}|a{15}b{15}|a{16}b{16}|a{17}b{17}|a{18}b{18}|a{19}b{19}|a{20}b{20}|
a{21}b{21}|a{22}b{22}|a{23}b{23}|a{24}b{24}|a{25}b{25}|a{26}b{26}|a{27}b{27}|a{28}b{28}|a{29}b{29}|a{30}b{30}|
a{31}b{31}|a{32}b{32}|a{33}b{33}|a{34}b{34}|a{35}b{35}|a{36}b{36}|a{37}b{37}|a{38}b{38}|a{39}b{39}|a{40}b{40}|
a{41}b{41}|a{42}b{42}|a{43}b{43}|a{44}b{44}|a{45}b{45}|a{46}b{46}|a{47}b{47}|a{48}b{48}|a{49}b{49}|a{50}b{50}|
a{51}b{51}|a{52}b{52}|a{53}b{53}|a{54}b{54}|a{55}b{55}|a{56}b{56}|a{57}b{57}|a{58}b{58}|a{59}b{59}|a{60}b{60}|
a{61}b{61}|a{62}b{62}|a{63}b{63}|a{64}b{64}|a{65}b{65}|a{66}b{66}|a{67}b{67}|a{68}b{68}|a{69}b{69}|a{70}b{70}|
a{71}b{71}|a{72}b{72}|a{73}b{73}|a{74}b{74}|a{75}b{75}|a{76}b{76}|a{77}b{77}|a{78}b{78}|a{79}b{79}|a{80}b{80}$/
Хороший пример задачи которую богопротивно решать регэкспами.
+1
я понял, чем отличается первое заблуждение от второго.
но почему они называются одинаково?
но почему они называются одинаково?
0
В PCRE эта возможность так и не включена.
Cуществует конструкция вида ?R
0
хм.
Ну что можно сказать — при всей своей ухватистости микроскопы сильно проигрывают молоткам.
Просто на минутку нужно представить ЧТО делает // и что делает substr.
«Регулярка» == машина регулярных выражений. Это подъязык, с выполнением выражения в подпроцессе. Это дорого, но умно.
Substr == выкусыватель подстроки (с возможностью замены). Он дешев но туп. Он не сможет найти 3 буквы «а» идущие где-то в конце строки.
Для каждой задачи существует оптимальный инструмент ее решения, но это же прописная истина.
Ровно как и то, что для каждой задачи существует подмножество оптимальных решений, зависящих от конкретизации условий. Выигрываем в силе — проигрываем в расстоянии. Выигрываем в охвате (универсальности) — проигрываем в скорости.
В общем — не понял, что Вы хотели сказать топиком.
Ну что можно сказать — при всей своей ухватистости микроскопы сильно проигрывают молоткам.
Просто на минутку нужно представить ЧТО делает // и что делает substr.
«Регулярка» == машина регулярных выражений. Это подъязык, с выполнением выражения в подпроцессе. Это дорого, но умно.
Substr == выкусыватель подстроки (с возможностью замены). Он дешев но туп. Он не сможет найти 3 буквы «а» идущие где-то в конце строки.
Для каждой задачи существует оптимальный инструмент ее решения, но это же прописная истина.
Ровно как и то, что для каждой задачи существует подмножество оптимальных решений, зависящих от конкретизации условий. Выигрываем в силе — проигрываем в расстоянии. Выигрываем в охвате (универсальности) — проигрываем в скорости.
В общем — не понял, что Вы хотели сказать топиком.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Осторожно! Регекспы!