Автор Тема: Perl регулярен израз  (Прочетена 7418 пъти)

qwerty11

  • Напреднали
  • *****
  • Публикации: 23
    • Профил
Perl регулярен израз
« -: Apr 12, 2012, 12:52 »
Здравейте, в момента ползвам един и същ Perl скрипт на няколко машини в къщи и на работа.Версията е This is perl, v5.10.1 (*) built for i486-linux-gnu-thread-multi
Тук всичко работи ОК.
Този същия скрипт го качих на http://webzone.smshosting.bg като там версията ми показва че е This is perl, v5.8.8 built for x86_64-linux-thread-multi.
Ето и скрипта:
Код
GeSHi (Perl):
  1. #!/usr/bin/perl
  2.  
  3. print "Content-type: text/html \n\n";
  4.  
  5. print "<html>";
  6. print "<head><title>Hello World Form</title><meta content=\"text/html; charset=windows-1251\" http-equiv=\"Content-Type\"></head>";
  7. print "<body>";
  8. $value = "345х тетрадки 45х молива 110х райрани ризи";
  9. #print "$value\n <br>";
  10.  
  11.  
  12. @FormToArray = split(/(?=\d+)/,$value);
  13. foreach $form (@FormToArray){
  14.   @arraycontract = split(' ',$form);
  15.   $countplant = shift(@arraycontract);
  16.   $contractplant = join(' ',@arraycontract);
  17.   $contractplantlc = lc($contractplant);
  18.   $countplant =~ s/[^0-9]*//g;
  19.   print "$countplant $contractplantlc\t <br>";
  20. }
  21. print "</body>";
  22. print "</html>";
  23.  

целта е да стане това:
345 тетрадки
45 молива
110 райрани ризи

И работи на perl, v5.10.1

Проблема се явява реда @FormToArray = split(/(?=\d+)/,$value); при версия perl, v5.8.8 на хостинга http://webzone.smshosting.bg
и по-точно \d+ като на http://webzone.smshosting.bg въобще не зачита знака +  и там се показва като
3
4
5 тетрадки
4
5 молива
1
1
0 райрани ризи

Интересува ме версията ли на Perl прави проблем, и ако има друг начин по който да тръгне скрипта там. Няма да се обидя и ако някой коментира кода.
« Последна редакция: Jun 05, 2012, 00:20 от VladSun »
Активен

Demayl

  • Напреднали
  • *****
  • Публикации: 104
  • Distribution: XUbuntu,FreeBSD
  • Window Manager: Xfce
    • Профил
    • WWW
Re: Perl регулярен израз
« Отговор #1 -: Apr 12, 2012, 14:01 »
Код
GeSHi (Perl):
  1. @FormToArray = split(/(?=\d+)/,$value);
  2. foreach $form (@FormToArray){
  3.   @arraycontract = split(' ',$form);
  4.   $countplant = shift(@arraycontract);
  5.   $contractplant = join(' ',@arraycontract);
  6.   $contractplantlc = lc($contractplant);
  7.   $countplant =~ s/[^0-9]*//g;
  8.   print "$countplant $contractplantlc\t <br>";
  9. }
  10.  
Това няма нужда.
Виж това :
Код
GeSHi (Perl):
  1. while ( $value =~ /(\d+)х\s*(.*?)\s*(?=(\d|$))/g ) {
  2.        print $1." ".$2."\t <br>";
  3. }
« Последна редакция: Jun 05, 2012, 00:21 от VladSun »
Активен

qwerty11

  • Напреднали
  • *****
  • Публикации: 23
    • Профил
Re: Perl регулярен израз
« Отговор #2 -: Apr 12, 2012, 15:56 »
Мерси The_Ghost
Твоя скрипт стана и между другото е доста симпатичен, ще го изплагиатствам за моите нужди.
И все пак ме дразни защо
Код
GeSHi (Perl):
  1. @FormToArray = split (/(?=\d+)/, $value);
в единия случай запазва разделителя, а на хостинга всяка цифра я шляпа като отделен елемент.
« Последна редакция: Jun 05, 2012, 00:22 от VladSun »
Активен

Naka

  • Напреднали
  • *****
  • Публикации: 3462
    • Профил
Re: Perl регулярен израз
« Отговор #3 -: Apr 12, 2012, 15:57 »
(?=\d+) това е Lookahead.

Преди като си играх с Lookahead и Lookbehind - но не в перл а със pcre, имаше значение дали патъна който се гледа /напед или назад е с фиксирана дължина или е с променлива. При теб е с \d+ което не е фиксирсан стринг.

Незнам дали е това проблема но имаше много разлики за интерпретирането на Lookahead/behind при отделните енджини за регулярни изрази. При пърл едно при java било друго, при pcre трето, Затова може да получваш различни резултати с различна версия на perl.


Например pcre позволява променлива дължина на стринга при Lookahead и (?=\d+) би трябвало да е правилно и да работи. Но пък забранява всякъкви + * ? при Lookbehind ??? ??? ???
Може просто версията на перл да не подържа Lookahead с променлива дължина и затова + да се игнорира.

пробвай да го сложиш в скоби (?=(\d+)) или пък търси друго решение без Lookahead/behind за да работи навсякъде.

« Последна редакция: Apr 12, 2012, 16:02 от Naka »
Активен

Perl - the only language that looks the same before and after encryption.

Demayl

  • Напреднали
  • *****
  • Публикации: 104
  • Distribution: XUbuntu,FreeBSD
  • Window Manager: Xfce
    • Профил
    • WWW
Re: Perl регулярен израз
« Отговор #4 -: Apr 12, 2012, 18:00 »
Мерси The_Ghost
Твоя скрипт стана и между другото е доста симпатичен, ще го изплагиатствам за моите нужди.
И все пак ме дразни защо @FormToArray = split (/(?=\d+)/, $value); в единия случай запазва разделителя, а на хостинга всяка цифра я шляпа като отделен елемент.

Изплагиатствай го :D, иначе случая е както го описа Naka. Макар че ако не го поддържа ще гръмне.
Рядко ползвам split, защото в повечето случаи с regex се вършат нещата. Макар че split-a е малко по-бърз, но ако го викнеш няколко пъти и regex-a става по бърз за дадено нещо. А и хубавото на perl  е че всичко става по всякакъв начин :D
« Последна редакция: Apr 12, 2012, 18:15 от The_Ghost »
Активен

SmashThePain

  • Напреднали
  • *****
  • Публикации: 21
    • Профил
Re: Perl регулярен израз
« Отговор #5 -: May 31, 2012, 23:22 »
Сложни ungreedy операции не ти трябват в случая. Да не говорим, че стринга ако ти е на повече от един ред точката няма да мачне новия ред. Аз като цяло на ungreedy неща въобще не съм фен. Ungreedy е измислено с една основна цел. Да предотвратява убийствен backtracking в ала Perl енджини за регулярни изрази. За пример виж енджина на Томпсън дали ще намериш backtracking.

Няма да се отплесвам. Може да си опростиш израза с negation, ето така:
Код:
/(\d+)x([^\d]+)/g


И "екс" - x е различно от буквата "х".
Активен

Demayl

  • Напреднали
  • *****
  • Публикации: 104
  • Distribution: XUbuntu,FreeBSD
  • Window Manager: Xfce
    • Профил
    • WWW
Re: Perl регулярен израз
« Отговор #6 -: Jun 01, 2012, 12:10 »
Сложни ungreedy операции не ти трябват в случая. Да не говорим, че стринга ако ти е на повече от един ред точката няма да мачне новия ред. Аз като цяло на ungreedy неща въобще не съм фен. Ungreedy е измислено с една основна цел. Да предотвратява убийствен backtracking в ала Perl енджини за регулярни изрази. За пример виж енджина на Томпсън дали ще намериш backtracking.

Няма да се отплесвам. Може да си опростиш израза с negation, ето така:
Код:
/(\d+)x([^\d]+)/g


И "екс" - x е различно от буквата "х".

Точно x си е буквата x, виж ако го напишеш \x за какво служи ( ако говориш за екс ). Да ако е на 2 реда примерно :
5 тет
радки - няма да го хване, защото не това се търсеше . Идеята е че сигурно ако е на 2+ реда, значи нещо не е ок и едва ли ще е редно да се вземе. Backtrackinga на perl - мисля че е основната идея тук !?
/(\d+)x([^\d]+)/g - вместо такъв negotation ( много тежък, може да пуснеш debug и да видиш ), може да е с \D+ .
Иначе съм съгласен, че това е по-добрия вариант . Предишното така ми прещрака  ;D
« Последна редакция: Jun 01, 2012, 12:14 от The_Ghost »
Активен

SmashThePain

  • Напреднали
  • *****
  • Публикации: 21
    • Профил
Re: Perl регулярен израз
« Отговор #7 -: Jun 01, 2012, 13:43 »
@The_Ghost  тежко за какво, за компилиране или за изпълнение? И в двата случая:
Код
GeSHi (Perl):
  1. /\D+/
  2. /[^\d]+/
  3.  

Няма никакъв backtracking и подозирам че времето за изпълнение ще са много близки. Аз лично предпочитам char class от гледна точка, че е лесно за добавяне на нови символи, но това са дреболии.

За backtracking-а може да говорим много. Просто енджините ала Perl могат да имат катастрофален backtracking. Имат тъй наречените патологични изрази. Та ungreedy е пачване на по-голям backtracking. Само заради това писах в темата. Ако може да напишеш регулярен израз без backtracking и естествено без ungreedy нещата ще са доста по-добре.

Също за оптимизации на Perl изрази е хубаво да се ползват atomic group и atomic repetition. Така например всеки лаик който пише:
Код
GeSHi (Perl):
  1. /.+<\/head>/
  2.  


И се чуди защо по дяволите му е бавен израза, ако го беше написал:

Код
GeSHi (Perl):
  1. /.++<\/head>/
  2.  

Щеше да разбере, че има backtracking от края на стринга обратно до `</head>`.

« Последна редакция: Jun 05, 2012, 00:22 от VladSun »
Активен

Demayl

  • Напреднали
  • *****
  • Публикации: 104
  • Distribution: XUbuntu,FreeBSD
  • Window Manager: Xfce
    • Профил
    • WWW
Re: Perl регулярен израз
« Отговор #8 -: Jun 01, 2012, 14:10 »
Ето ти резултат от (\D+) и ([^\d]+) s Benchmark модула -
\D+ - ~236000/s
[^\d]+ - ~170000/s

В случая [^\d]+ прави много повече стъпки.

Иначе за примера е добре даден с .+ и .++ , по проста грешка която правят е с .* и .*?  и се чудят защо не хваща първото срещнато след .* , а хваща последното. Не е катастрофален backtrackinga - просто хората го пишат така .
« Последна редакция: Jun 01, 2012, 14:13 от The_Ghost »
Активен


Подобни теми
Заглавие Започната от Отговора Прегледи Последна публикация
Кирилица и Perl
Общ форум
ivanatora 2 4534 Последна публикация Mar 08, 2005, 18:45
от picmaster
Трасиране на стека на perl
Web development
CaBA 8 6562 Последна публикация May 18, 2005, 20:48
от CaBA
perl-DBI
Настройка на програми
overclocked 0 3229 Последна публикация May 15, 2005, 12:34
от overclocked
Perl и md5
Web development
batsve 11 6228 Последна публикация Aug 05, 2005, 15:01
от batsve
Редактиране на PDF документи с Perl
Общ форум
mhydra 5 5732 Последна публикация Aug 22, 2005, 08:30
от