🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.perl
10 messages
10 total messages Started by Qrczak Fri, 10 Apr 1998 08:07
/\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g
#1203
Author: Qrczak
Date: Fri, 10 Apr 1998 08:07
39 lines
2416 bytes
Chciałbym się spytać, czy coś takiego jak w Temacie ma obowiązek
zadziałać tak jak chcę. W praktyce u mnie działa, ale nie wiem, czy
można zakładać, że tak będzie zawsze...

Chodzi mi mianowicie o to "\(.*?\)|.*?". Kolejność obu możliwości ma
znaczenie! Chcę żeby w przypadku kiedy zaczynamy od "+(", wziąć wszystko
aż do następnego ")+", łącznie z ewentualnymi wewnętrznymi "+".
Teoretycznie on mógłby dopasować to do drugiego wariantu: ".*?",
i zatrzymać się na pierwszym "+" w nawiasie, jednak tego nie robi
- i dobrze! ale może któraś wersja zacznie.

Mogę oczywiście zamienić to na "\(.*?\)|[^(].*?|" albo nawet na
"\((?:[^)]|\)(?!\+))*\)|[^+(][^+]*|", nie ufając ".*?" i mając pewność, 
że zawsze będzie dobrze (o ile się nie pomyliłem), ale, jak widać,
komplikując wyrażenie. Co radzicie?

A może zaproponujecie lepszą metodę na podzielenie napisu postaci:
    1+222+(3+(5)6+7)+8
na:
    1  222  (3+(5)6+7)  8
niż:
    map { s/^\+//; różne_inne_rzeczy; }
    ("+" . ów_napis) =~ /powyższe_wyrażenie/g
?

BTW: W tych nawiasach będą komendy basha. Przyjąłem założenie, że po
prostu nie może w nich wystąpić ciąg ")+". Lepiej by było rozpoznawać
zagnieżdżenie nawiasów, czego nie da się załatwić jednym wyrażeniem
regularnym, ale może macie pomysł, jak to w miarę prosto zrobić?
Oczywiście nawiasy wyeskejpowane albo w cudzysłowach mają się nie
liczyć, jak to w szelu. Załóżmy, że komenda jest poprawnie zbudowana.
Pewnie jednak szkoda zachodu, ")+" można wyeskejpować jeśli ktoś
przypadkiem będzie tego potrzebował...

-- 
                                 QRCZAK
    __("<              Marcin Kowalczyk
    \__/              qrczak@knm.org.pl
     ^^      http://qrczak.home.ml.org/
Re: /\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g
#1204
Author: Qrczak
Date: Fri, 10 Apr 1998 09:20
19 lines
1560 bytes
On Fri, 10 Apr 1998, Qrczak wrote:

> Mogę oczywiście zamienić to na "\(.*?\)|[^(].*?|" albo nawet na
> "\((?:[^)]|\)(?!\+))*\)|[^+(][^+]*|", nie ufając ".*?" i mając pewność, 
> że zawsze będzie dobrze (o ile się nie pomyliłem), ale, jak widać,
> komplikując wyrażenie. Co radzicie?

Byłbym zapomniał - jeśli jest "\(.*?\)|.*?", to błąd typu
    1+(23)4+5
sam zostanie później wykryty. Jeśli zaś zamienię na któreś powyżej, to
/wyrażenie/g w ogóle tego kawałka nie zauważy. Gdyby nie to, to pewnie
bym zmienił na bezpieczniejszą wersję, a tak to trzeba by się bardziej
pogimnastykować, żeby nic nie poginęło.

-- 
                                 QRCZAK
    __("<              Marcin Kowalczyk
    \__/              qrczak@knm.org.pl
     ^^      http://qrczak.home.ml.org/
Re: /\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g - off topic
#1205
Author: Adam Karpierz
Date: Fri, 10 Apr 1998 11:15
57 lines
2866 bytes
Qrczak napisal:
[...]
> Chciałbym się spytać, czy coś takiego jak w Temacie ma 
> obowiązek zadziałać tak jak chcę. W praktyce u mnie 
> działa, ale nie wiem, czy można zakładać, że tak będzie
> zawsze...
> 
> Chodzi mi mianowicie o to "\(.*?\)|.*?". Kolejność obu 
> możliwości ma znaczenie! Chcę żeby w przypadku kiedy 
> zaczynamy od "+(", wziąć wszystko aż do następnego 
> ")+", łącznie z ewentualnymi wewnętrznymi "+". 
> Teoretycznie on mógłby dopasować to do drugiego 
> wariantu: ".*?", i zatrzymać się na pierwszym "+" w 
> nawiasie, jednak tego nie robi - i dobrze! ale może 
> któraś wersja zacznie.
> 
> Mogę oczywiście zamienić to na "\(.*?\)|[^(].*?|" albo 
> nawet na "\((?:[^)]|\)(?!\+))*\)|[^+(][^+]*|", nie ufając 
> ".*?" i mając pewność, że zawsze będzie dobrze (o ile 
> się nie pomyliłem), ale, jak widać, komplikując wyrażenie. 
> Co radzicie?
> 
> A może zaproponujecie lepszą metodę na podzielenie 
> napisu postaci:
>     1+222+(3+(5)6+7)+8
> na:
>     1  222  (3+(5)6+7)  8
> niż:
>     map { s/^\+//; różne_inne_rzeczy; }
>     ("+" . ów_napis) =~ /powyższe_wyrażenie/g
> ?
> 
> BTW: W tych nawiasach będą komendy basha. Przyjąłem 
> założenie, że po prostu nie może w nich wystąpić ciąg ")+". 
> Lepiej by było rozpoznawać zagnieżdżenie nawiasów, 
> czego nie da się załatwić jednym wyrażeniem
> regularnym, ale może macie pomysł, jak to w miarę prosto 
> zrobić?
> Oczywiście nawiasy wyeskejpowane albo w cudzysłowach 
> mają się nie liczyć, jak to w szelu. Załóżmy, że komenda 
> jest poprawnie zbudowana. Pewnie jednak szkoda zachodu, 
> ")+" można wyeskejpować jeśli ktoś przypadkiem będzie 
> tego potrzebował...

Zaniemowilem z wrazenia... Calkiem powaznie mowie !
Qurczaku, juz nigdy nikomu nie powiem ze jest glupi 
jak qura :))).

PS: Moze ktos da znac Pawlowi Gajdzie zeby juz nie szukal 
      zaciemniacza do Perla. Jest na www.qurczak.com.pl :).
      Tyle ze nie darmowy :).

-- 
Pozdrawiam i zycze wszystkim Perlowistkom i Perlowiczom
Wesolych i Spokojnych Swiat (a Qurczakowi szczegolnie:)
   
Adam Karpierz   
Re: /\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g
#1206
Author: Michal Mosiewicz
Date: Fri, 10 Apr 1998 18:31
26 lines
1866 bytes
Qrczak wrote:

> Chodzi mi mianowicie o to "\(.*?\)|.*?". Kolejność obu możliwości ma
> znaczenie! Chcę żeby w przypadku kiedy zaczynamy od "+(", wziąć wszystko
> aż do następnego ")+", łącznie z ewentualnymi wewnętrznymi "+".
> Teoretycznie on mógłby dopasować to do drugiego wariantu: ".*?",
> i zatrzymać się na pierwszym "+" w nawiasie, jednak tego nie robi
> - i dobrze! ale może któraś wersja zacznie.

Nie powinna. Zasadą działania regexpów jest zachłanność. Jeśli coś może
pasować do nieustalonej ilości znaków, to dopasowywuje się je na maksa.

Natomiast przyznam, że wyrażenie .*? mógłbyś spokojnie zastąpić
następującym wyrażeniem:

Tak, tu jest pusto - to nie pomyłka. Bo takie wyrażenie jest równe
wyrażeniu pustemu. .* wyszukuje 0 lub więcej dowolnych znaków. Znak
zapytania każe mu wyszukiwać jak najmniej się da. Zatem .*? nic nie
wyszukuje. Bo skoro może być zero znaków, to w takim razie zero znaków
jest w sam raz (mniej już się chyba nie da, nie?)

Michał

-- 
WWW: http://www.lodz.pdi.net/~mimo  tel: Int. Acc. Code + 48 42 148340
add: Michal Mosiewicz  *  Bugaj 66 m.54 *  95-200 Pabianice  *  POLAND
Re: /\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g
#1207
Author: Qrczak
Date: Fri, 10 Apr 1998 20:41
42 lines
2321 bytes
On Fri, 10 Apr 1998, Michal Mosiewicz wrote:

> Natomiast przyznam, że wyrażenie .*? mógłbyś spokojnie zastąpić
> następującym wyrażeniem:
[...]

man perlre:

       By default, a quantified subpattern is "greedy", that is,
       it will match as many times as possible (given a
       particular starting location) while still allowing the
       rest of the pattern to match.  If you want it to match the
       minimum number of times possible, follow the quantifier
       with a "?".  Note that the meanings don't change, just the
       "greediness":

           *?     Match 0 or more times
           +?     Match 1 or more times
           ??     Match 0 or 1 time
           {n}?   Match exactly n times
           {n,}?  Match at least n times
           {n,m}? Match at least n but not more than m times

BTW: Nawet gdyby to nie miało specjalnego znaczenia, to .*? byłoby
równoważne .*, a nie napisowi pustemu.

Moje pytanie sprowadza się do tego: Czy jeśli przy czymś takim:
  ( wyr1 | wyr2 )
w danym miejscu pasują oba wyrażenia, to zostanie użyte wyr1, czy też
z góry nie wiadomo?

Argument za tym, żeby z tego skorzystać: Upraszcza to konkretny problem;
w praktyce nie zaobserwowałem, żeby to nie zadziałało w ten sposób.

Argument przeciwny: Być może nie musi tak zadziałać - wtedy po prostu
_trzeba_ pomęczyć się nie korzystając z tego.

-- 
                                 QRCZAK
    __("<              Marcin Kowalczyk
    \__/              qrczak@knm.org.pl
     ^^      http://qrczak.home.ml.org/
Re: /\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g
#1208
Author: Krzysztof Koczyjan
Date: Tue, 14 Apr 1998 03:14
18 lines
1222 bytes
Qrczak wrote:

> A może zaproponujecie lepszą metodę na podzielenie napisu postaci:
>     1+222+(3+(5)6+7)+8
> na:
>     1  222  (3+(5)6+7)  8

Proponowalbym :
while( $s =~ /\G(\(.*?\)|.*?)(\+|$)/g ){
       do_something($1);
}

Jak swoja droga to czegos takiego jak (3+(5)6+7), gdzie liczba nawiasow
sie zgadza nie da sie zapisac przy pomocy wyrazenia regularnego. 
Powyzszy programik podobnie jak Twoj przelknie cos jak ((((((((()+.

Mam nadzieje, ze w czyms pomoglem
	KK
Re: /\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g
#1209
Author: Qrczak
Date: Tue, 14 Apr 1998 09:32
22 lines
1616 bytes
On Mon, 13 Apr 1998, Krzysztof Koczyjan wrote:

> while( $s =~ /\G(\(.*?\)|.*?)(\+|$)/g ){
>        do_something($1);
> }

Faktycznie, można i tak, dzięki.

Z tym że pozostaje ta sama niepewność, czy on nie dopasuje początku
czegoś w rodzaju (x+y) akurat do .*? zamiast do \(.*?\). Nigdy nie
słyszałem o regule, że jeśli coś pasuje do kilku części oddzielonych |,
to jest brana pierwsza od lewej... ale rzeczywistość zdaje się to
potwierdzać, więc tak w końcu zrobiłem. Zamiana .*? na coś w rodzaju
[^(].*?| również tutaj spowowowałaby zupełne zignorowanie błędnych
kawałków w stylu ...+(x)y+..., a nawet gorzej, bo by się zignorowało
wszystko co znajduje się za tym.

-- 
                                 QRCZAK
    __("<              Marcin Kowalczyk
    \__/              qrczak@knm.org.pl
     ^^      http://qrczak.home.ml.org/
Re: /\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g
#1212
Author: Piotr Piatkowski
Date: Tue, 14 Apr 1998 17:43
23 lines
1946 bytes
Qrczak <qrczak@knm.org.pl> wrote:
: czegoś w rodzaju (x+y) akurat do .*? zamiast do \(.*?\). Nigdy nie
: słyszałem o regule, że jeśli coś pasuje do kilku części oddzielonych |,
: to jest brana pierwsza od lewej... ale rzeczywistość zdaje się to
: potwierdzać, więc tak w końcu zrobiłem.

Potraktowałem to jako wyzwanie - faktycznie w manualu nie znalazłem 
nic na temat kolejności dopasowywania alternatyw, więc zajrzałem do 
źródeł perla :-)

Nie żebym wiele z tego zrozumiał, ale wydaje mi się że algorytm jest 
taki, że perl próbuje dopasować kolejne gałęzie alternatywy (w 
kolejności w jakiej wystąpiły w wyrażeniu) i jeżeli któraś z nich 
pasuje, to już nie sprawdza kolejnych. Oczywiście poza sytuacją gdy 
nie uda mu się dopasować całego wyrażenia i musi wykonać backtrace po
czym spróbować znowu (np. w innym miejscu).

Więc - co też potwierdza praktyka - wszystko wskazuje na to że brana 
jest zawsze pierwsza od lewej pasująca część alternatywy, o ile tylko
umożliwia dopasowanie całego wyrażenia.

-- 
Piotr Piątkowski, Uczelniane Centrum Informatyki, AGH Krakow, POLAND
Re: /\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g
#1210
Author: Krzysztof Koczyjan
Date: Tue, 14 Apr 1998 22:18
32 lines
1824 bytes
Qrczak wrote:
> 
> On Mon, 13 Apr 1998, Krzysztof Koczyjan wrote:
> 
> Z tym że pozostaje ta sama niepewność, czy on nie dopasuje początku
> czegoś w rodzaju (x+y) akurat do .*? zamiast do \(.*?\). Nigdy nie
> słyszałem o regule, że jeśli coś pasuje do kilku części oddzielonych 

Perl uzywa tzw "leniwego" obliczania wyrazen regularnych - zatrzymuje
sie na pierwszym pasujacym wzorcu - i jak doswidczenia pokazuja sprawdza
wzorce od lewej strony. 
"Pelne" obliczanie zatrzymuje sie na najdluzszym z pasujacych, niestety
wymaga to przejrzenia wszystkich kombinacji. Wymaga to niestety wiecej
czasu, a perl ma dzialac szybko :-).

W przypadku ktory opisujesz nie akurat problemu (.*)\+ jest dluzsze niz
(.*\+ , tak ze zostanie wybrane wlasciwe, ale jesli chcesz miec pewnosc
to mozna uzyc czegos takiego:
while(1){
	if( /\G(\(.*?\))(\+|$)/gc ){
		fun($1);
	}
	elsif( /\G(.*?)(\+|$)/gc ){
		fun($1);
	}
	else{
		last;
	}
}

Pozdrowienia
	KK
Re: /\+(?:\(.*?\)|.*?)(?:$|(?=\+))/g
#1211
Author: Qrczak
Date: Wed, 15 Apr 1998 09:45
26 lines
1554 bytes
On Tue, 14 Apr 1998, Krzysztof Koczyjan wrote:

> while(1){
> 	if( /\G(\(.*?\))(\+|$)/gc ){
> 		fun($1);
> 	}
> 	elsif( /\G(.*?)(\+|$)/gc ){
> 		fun($1);
> 	}
> 	else{
> 		last;
> 	}
> }

Tu akurat problem jest drobny: w perlu 5.001 nie było jeszcze /c,
a podobno ta wersja jest jeszcze często używana... Ale można to
przerobić zjadając pasujące człony i szukając nowych tylko na początku,
tyle że to już nie będzie takie eleganckie.

Dziękuję wszystkim za pomoc.

-- 
                                 QRCZAK
    __("<              Marcin Kowalczyk
    \__/              qrczak@knm.org.pl
     ^^      http://qrczak.home.ml.org/
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads