Regexp помогите написать на перле
Я бы сначала сохранил все [pre]...[/pre] отдельно, потом сделал всё что надо со строкой, а затем вернул [pre]...[/pre] на место.
Спасибо.
$_=qq~
asd fdfg[Q] [pre]ee ffd x[Q]x
ee[Q][/pre][Q] [Q] asd fdfg[Q] [pre]
ee ffd x[Q]x ee[Q][/pre]
[Q] [Q]
~;
print "$_\n";
<a href="mailto:(\[pre\].*?\[q\].*?\[/pre\])|\[Q\]@$1?">(\[pre\].*?\[q\].*?\[/pre\])|\[Q\]@$1?</a>"$1":"\<Q\>"@igse;
print "$_\n";
вывод:
[mobile100 vilfred]$ perl aaa.pl
asd fdfg[Q] [pre]ee ffd x[Q]x
ee[Q][/pre][Q] [Q] asd fdfg[Q] [pre]
ee ffd x[Q]x ee[Q][/pre]
[Q] [Q]
asd fdfg<Q> [pre]ee ffd x[Q]x
ee[Q][/pre]<Q> <Q> asd fdfg<Q> [pre]
ee ffd x[Q]x ee[Q][/pre]
<Q> <Q>
[mobile100 vilfred]$
лоигика такая: если существует переменная $1, то её печатать, иначе заменять \[Q\], которое по условию или "|"...
I A aaa.pl (perl) Row 6 Col 19 0:10 Ctrl-K H for help
#!/usr/bin/perl
$_=qq~
asd fdfg[Q] [pre]ee ffd x[Q]x
ee[Q][/pre][Q] [Q] asd fdfg[Q] [pre]
ee ffd x[Q]x ee[Q][/pre]
[Q] [Q]
~;
print "$_\n";
(\[pre\].*?\[q\].*?\[/pre\])|\[Q\]@$1?"$1":"\<Q\>"@igse;
print "$_\n";
почемуж не надо то? если для s! по документации предусмотрен ключ e, помимо ключей igsmox, почему бы им не воспользоваться?
Можно переписать в виде типа
$str = "всякая белиберда";
if($str =~ /всякие шаблоны/gise){
$str =~ s/всякие шаблоны2/всякие шаблоны3/gise;
}
А "?:" это условный оператор?
вопросительный знак - это минимализация действия квантификатора(ограничение жадности типа если a.*a - найдет все символы в строке(жадный находящиеся между самыми дальними adfggasdfa (подстроку dfggasdf то a.*?a найдет подстроку dfgg. Короче см. тут:
s/regex/условие?да:иначе/e
$str =~ (\[pre\].*?\[/pre\])|\[Q\]@$1?"$1":"\<Q\>"@igse;
Обнаружил, что
(.\n)*zzz
тормозит квадратично (есди в файле нет строки zzz). И даже понял почему.
Хммм... А почему?
Берёт второй символ, ...
...
= квадрат пополам.
Это лечится, если поставить вначале ^, но мне нужно было multiline.
Вообще глядя на этот пример легко понять, как вообще умеют тормозить НКА. Тормозить они умеют полиномиально (с любой наперёд заданной степенью соответствующей количеству значков * и + но не сильнее.
Например, (.|\n)*a(.|\n)*z на строке из aa...a будет тормозить кубически.
Берёт первый символ, начинает искать подстроку в оставшемся (линейно).Есть более эффективные способы поиска подстроки.
Берёт второй символ, ...
...
= квадрат пополам.
ообще глядя на этот пример легко понять, как вообще умеют тормозить НКА. Тормозить они умеют полиномиально (с любой наперёд заданной степенью соответствующей количеству значков * и + но не сильнее.IMHO, автомат работает за линейное время. Проблема скорее всего в скорости построения этого автомата, но оно ограничено полиномом конечной степени от длины регулярного выражения.
Например, (.|\n)*a(.|\n)*z на строке из aa...a будет тормозить кубически.
Я бы хотел обратить ваше внимание на то, что автомат не ищет подстроку. Ищет подстроку вот такой регексп: "zzz"
А у нас тут "(.|\n)*zzz" - это разные регеспы, и они по разному работают.
>IMHO, автомат работает за линейное время.
>Проблема скорее всего в скорости построения этого автомата
Не уверен - не пизди. Я - уверен, я проверял.
Я бы хотел обратить ваше внимание на то, что автомат не ищет подстроку. Ищет подстроку вот такой регексп: "zzz"Если это ищет автомат, то нам посрать что он ищет. Автоматы работают не более чем за линейное время от длины подаваемой строки.
А у нас тут "(.|\n)*zzz" - это разные регеспы, и они по разному работают.
Не уверен - не пизди.Если ты уверен, то напиши где я напиздел. Иначе - не пизди сам.
Я - уверен, я проверял.Что именно ты проверял? Есть теория - я тебе написал с какой скоростью и что должно работать. Если ты проверял что-то другое, то напиши что и как.
В общем случае, сложность автомата - это кол-во состояний на кол-во условий перехода.
В идеале за счет расхода памяти - можно сделать, чтобы переходы выполнялись за константное время.
Но если, например, строки уникодные - то на каждое состояние будет уходить 65к * 4 = 260к
В сложных случаях, например, когда есть параллельные ветки и т.д, - кол-во состояний тоже может расти экспонециально.
например, в запросе:
[Hh][Ee][Ll][Ll][Oo], [Ww][Oo][Rr][Ll][Dd]
кол-во состояний получается 1024
Соответственно, честные автоматы (с одним состоянием и константным временем перехода) делаются не всегда
честные автоматыЕсли 1024 состояния закодированы 10 битами, что ж в этом нечестного? Просто формулу перехода сложнее вычислять, чем просто в таблицу слазить.
чтобы переходы выполнялись за константное времяКонстантные по сравнению с чем? Все переходы во всех автоматах за одно и то же время? Вряд ли. Таблица может в кеш не влезть и т.п.
Но если, например, строки уникодные - то на каждое состояние будет уходить 65к * 4 = 260кЭто без оптимизаций и с расчётом на максимум 256^4 состояний. Даже если хранить не плоскую таблицу, а как-нибудь изощряться, то всё равно автомат не начнёт работать за полиномиальное время, где степень полинома зависит от чиса звёздочек.
например, в запросе:Почему-то я сильно сомневаюсь, что автомат, разбирающий этот регэксп, будет иметь 1024 состояния. Ну если не рассматривать тот вариант, что при желании такое можно придумать, а при ещё большем желании можно и ещё развернуться, но цель-то не в этом.
[Hh][Ee][Ll][Ll][Oo], [Ww][Oo][Rr][Ll][Dd]
кол-во состояний получается 1024
Но если, например, строки уникодные - то на каждое состояние будет уходить 65к * 4 = 260кЕщё... Памяти нужно не больше чем
C * (<число_состояний_автомата> * <число_различных_символов_в_регэкспе> + <число_символов_в_алфавите>)
с сохранением линейности автомата.
Поэтому каждое состояние не должно занимать столько места. Только в случае если у нас в регэкспе стоят все или почти все возможные символы.
PS. Хотя ты, наверное, и сам уже догадался.
Проверял я то, что автомат строится быстро, а ищет медленно.
Причина этого в том, как мне кажется, что они не напускают автомат на всю строку сразу, а осуществляют бэктрекинг ручками (мб чтобы размер автомата не рос слишком быстро, не знаю).
То, как это происходит, я описал выше.
Если у кого-нибудь есть под рукой что-нибудь кроме .NET Regex Engine, можно проверить, вдруг это чисто его особенность.
Типа, как долго работает .*zzz на длинной строке aaa...a
ЗЫ: К чему это вы всё про уникод и таблички говорите? Понятно, что там какое-то специальное представление, поиск по которому всё равно занимает O(1) или O(ln(n (что одно и то же как правило).
> <число_символов_в_алфавите>) с сохранением линейности автомата
Каким образом тогда будет осуществляться константность перехода?
т.е. каким образом будет осуществляться уход от множества if-ов:
case State5:
if (ch == 'a')
state = State6;
if (ch == 'd')
state = State4;
if (IsDigit(ch
state = State7;
//и т.д.
имхо, для константности перехода - памяти все-таки нужно пропорционально 'кол-во состояний * кол-во символов алфавита'
Если у кого-нибудь есть под рукой что-нибудь кроме .NET Regex Engine, можно проверить, вдруг это чисто его особенность.В тестах ниже файлы содержат одну строку из букв "a" длиной соответсвующей названию:
Типа, как долго работает .*zzz на длинной строке aaa...a
$ time grep ".*zzz" file1M
real 0m0.024s
user 0m0.010s
sys 0m0.012s
$ time grep ".*zzz" file16M
real 0m0.298s
user 0m0.185s
sys 0m0.099s
$ time grep ".*zzz" file128M
real 0m2.608s
user 0m1.413s
sys 0m0.887s
Результаты выглядят достаточно линейно...
.*zzz и (.*)zzz - очень разные вещи. Второй - и не регексп вовсе.
Каждому встречающемуся символу в регулярном выражении присваивается номер, всем остальным символам тоже присваивается один и тот же номер. (1-я таблица символ_алфавита->номер)
Дальше строится автомат уже над этими номерами. (2-я таблица состояние*номер->состояние).
Потестил sed-ом - вот результаты:
Действительно видна зависимость n^2 от длины строки. Фигня какая-то . Не поверил. Сделал на perl:
$ time sed 's/\(.*\)zzz/\1eee/' file8k > /dev/null
real 0m0.609s
user 0m0.602s
sys 0m0.003s
$ time sed 's/\(.*\)zzz/\1eee/' file16k > /dev/null
real 0m2.432s
user 0m2.414s
sys 0m0.013s
$ time sed 's/\(.*\)zzz/\1eee/' file32k > /dev/null
real 0m9.787s
user 0m9.676s
sys 0m0.024s
Результаты радикально отличаются. Осталось понять кто не прав...
$ cat 1.pl
#!/usr/bin/perl
$_ = <>;
s/(.*)zzz/$1eee/;
print $_;
$ time perl 1.pl < file1M > /dev/null
real 0m0.018s
user 0m0.011s
sys 0m0.006s
$ time perl 1.pl < file16M > /dev/null
real 0m0.279s
user 0m0.139s
sys 0m0.056s
$ time perl 1.pl < file128M > /dev/null
real 0m4.555s
user 0m1.073s
sys 0m0.555s
идем сюда
http://gibbon.kinnet.ru/uzhas/index.php
и вводим ето
(HvhEveLvlLvlOvoWvwOvoRvrLvlDvd)
получаем 22 состояния
кто-нить может дать строку, чтобы вершин в источнике было больше, чем символов в строке?:)
Без звездочек и отрицаний не интересно.
к тому же в примере [Hh][Ee][Ll][Ll][Oo], [Ww][Oo][Rr][Ll][Dd]
я не увидел звездочек=)
> к тому же в примере [Hh][Ee][Ll][Ll][Oo], [Ww][Oo][Rr][Ll][Dd]
значит, пример, неправильно - слишком простой.
Без звездочек и отрицаний не интересно.Разве от "звёздочек" намного хуже будет?
Оставить комментарий
Elina74
Чтобы заменял в строке, к примеру [Q] на <Q> за исключением тех случаев, когда [Q] находится внутри тегов [pre]...[/pre]Между тегами кроме всего прочего могут быть произвольные символы...