ACHTUNG. Das ist ein Archiv des alten forum.ruby-portal.de. Die aktuelle Mailingliste gibt es auf lists.ruby-lang.org/pipermail/ruby-de.

NOTICE. This is a ready-only copy of the old forum.ruby-portal.de. You can find the current mailing list at lists.ruby-lang.org/pipermail/ruby-de.

Die Programmiersprache Ruby

Blog|

Forum|

Wiki  


Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]

Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Oniguruma Bug?
BeitragVerfasst: 26 Apr 2007, 07:26 
Offline
Geselle
Benutzeravatar

Registriert: 09 Aug 2006, 11:49
Beiträge: 148
Siehe hier:



1
2
irb(main):001:0> "me".gsub(/.*/, "foo")
=> "foofoo"


Schlägt aber unter Ruby 1.8 ebenfalls fehl. Anscheinend wird der übrigbleibende Leerstring vom ersten Lauf nochmal gematcht.

Ist das jemanden schon mal untergekommen?

_________________
[code=]class<<self;define_method(%_>6E9@50>:DD:?8_.tr(%_0-f_,%_\_-t_)){|*_|@_\
=_};end;(Just another Ruby hacker!);(_,@_=@_;$><<_<<%_ _)while@_;$><<$/[/code]


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 26 Apr 2007, 15:01 
Offline
ri
Benutzeravatar

Registriert: 02 Jun 2006, 23:18
Beiträge: 702
Hallo,

das ist vermutlich eher ein Feature. Warum sollte sich die Regex-Maschine beim Substituieren anders verhalten als beim Auffinden von Treffern? Insofern macht es schon Sinn, was da passiert. Mit Perl kommt man übrigens auf dasselbe Ergebnis.

Grüße,
Matthias


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 26 Apr 2007, 15:21 
Offline
Geselle

Registriert: 01 Mai 2004, 09:50
Beiträge: 171
Wohnort: Purkersdorf
Zeigst du bitte mal deinen Perl-Code.

EDIT: Erledigt.
EDIT2: Zu spät editiert :)


Zuletzt geändert von mawe am 26 Apr 2007, 17:13, insgesamt 2-mal geändert.

Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 26 Apr 2007, 16:13 
Offline
Geselle
Benutzeravatar

Registriert: 09 Aug 2006, 11:49
Beiträge: 148
reima hat geschrieben:
Mit Perl kommt man übrigens auf dasselbe Ergebnis.


Tatsache, das ist mal interessant. Am besten also Zero Length matches vermeiden.

_________________
[code=]class<<self;define_method(%_>6E9@50>:DD:?8_.tr(%_0-f_,%_\_-t_)){|*_|@_\
=_};end;(Just another Ruby hacker!);(_,@_=@_;$><<_<<%_ _)while@_;$><<$/[/code]


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 26 Apr 2007, 16:59 
Offline
ri
Benutzeravatar

Registriert: 02 Jun 2006, 23:18
Beiträge: 702
mawe hat geschrieben:
Zeigst du bitte mal deinen Perl-Code.



1
2
3
4
5
6
7
8
#!/usr/bin/perl

use strict;

my $str = "me";
$str =~ s/.*/foo/g;

print $str; # => foofoo


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 26 Apr 2007, 19:10 
Offline
Interpreter

Registriert: 15 Mär 2005, 19:26
Beiträge: 6142
Wohnort: Karlsruhe
blackbird hat geschrieben:
Am besten also Zero Length matches vermeiden.

Die bieten diverse Überraschungen, wenn man nicht aufpasst.

Allerdings ist das Verhalten vollkommen erklärlich. Die Engine vermeidet es bei scan an der gleichen Stelle wieder aufzusetzen, wie beim letzten mal, wenn ein Leerstring erkannt wurde. Dann geht die Maschine implizit ein Zeichen weiter und hört auf, falls das nicht mehr geht.

Im aktuellen Fall erkennt der erste Durchlauf jedoch alle Zeichen (Greedy-Match), kann also getrost nach dem Match noch einmal das Muster versuchen. Da es am Ende den Leerstring erkennt, ist also alles O.K.

Danach ist es immer noch am Ende des Strings, versucht also ein Zeichen weiter zu gehen, was nicht mehr geht. Also ist die Arbeit getan.

Wenn die RegEx-Maschinen nicht diese Optimierung eingebaut hätten (ob es alle haben, weiss ich nicht), würde dieser Match in eine Endlosschleife münden, die irgendwann einmal wegen der vielen Ersetzungen (leer zu Zeichenfolge) den Speicher überlaufen lässt.

Dieses Fortschreiten sieht man sehr schön beim non-greedy Match

1
2
irb(main):001:0> "me".gsub(/.*?/, "foo")
=> "foomfooefoo"

_________________
WoNáDo.set_state!(:retired)


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 26 Apr 2007, 23:18 
Offline
Geselle
Benutzeravatar

Registriert: 09 Aug 2006, 11:49
Beiträge: 148
WoNáDo hat geschrieben:
Allerdings ist das Verhalten vollkommen erklärlich. Die Engine vermeidet es bei scan an der gleichen Stelle wieder aufzusetzen, wie beim letzten mal, wenn ein Leerstring erkannt wurde. Dann geht die Maschine implizit ein Zeichen weiter und hört auf, falls das nicht mehr geht.

Ich war das jetzt von Python gewohnt und da wird bei einem Leerstring als Rückstand nicht mehr gematcht:


1
2
>>> re.compile(r'.*').sub('foo', 'searchstring')
'foo'


Im aktuellen Fall erkennt der erste Durchlauf jedoch alle Zeichen (Greedy-Match), kann also getrost nach dem Match noch einmal das Muster versuchen. Da es am Ende den Leerstring erkennt, ist also alles O.K.

Zitat:
Dieses Fortschreiten sieht man sehr schön beim non-greedy Match

1
2
irb(main):001:0> "me".gsub(/.*?/, "foo")
=> "foomfooefoo"

Das ist aber ein generell erwünschtes verhalten. Siehe:


1
2
3
4
5
irb(main):001:0> "foo".gsub(//, ".")
=> ".f.o.o."
# bzw
>>> "foo".replace("", ".")
'.f.o.o.'

_________________
[code=]class<<self;define_method(%_>6E9@50>:DD:?8_.tr(%_0-f_,%_\_-t_)){|*_|@_\
=_};end;(Just another Ruby hacker!);(_,@_=@_;$><<_<<%_ _)while@_;$><<$/[/code]


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 27 Apr 2007, 12:24 
Offline
Interpreter

Registriert: 15 Mär 2005, 19:26
Beiträge: 6142
Wohnort: Karlsruhe
Da wurde für die Python-RegEx-Maschine offensichtlich eine andere Heuristik gewählt - aus welchem Grund auch immer.

Allerdings sind diese scannenden Matches oder Ersetzungen in Verbindung mit einem Muster, welches auch den Leerstring erkennt eigentlich ein Programmierfehler. Ich habe leider momentan kein Linux zur Verfügung, aber ich schätze fast, dass lex mit einem derartigen Muster als einzigem Element eine Endlosschleife produziert.

_________________
WoNáDo.set_state!(:retired)


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 15 Jun 2007, 19:34 
Offline
Interpreter

Registriert: 15 Mär 2005, 19:26
Beiträge: 6142
Wohnort: Karlsruhe
blackbird hat geschrieben:
Ich war das jetzt von Python gewohnt und da wird bei einem Leerstring als Rückstand nicht mehr gematcht...

WoNáDo hat geschrieben:
Da wurde für die Python-RegEx-Maschine offensichtlich eine andere Heuristik gewählt - aus welchem Grund auch immer.

Im Thread komplexes split bin ich direkt mit der Nase auf einen Vorteil von Pythons Heuristik gestossen. line.scan(/\G((?>\\.|[^\|])*)(?:\||$)/) liefert immer einen leeren Match am Ende, den man irgendwie beseitigen oder durch ein zusätzliches Look-Ahead im Muster vermeiden muss (line.scan(/\G(?=.)((?>\\.|[^\|])*)(?:\||$)/)).

Das ist nicht sonderlich schön und kann eventuell sogar zu Fehlern führen...

1
2
3
4
5
6
irb(main):001:0> "ab".scan(/\G(?=.)((?>\\.|[^\|])*)(?:\||$)/)
=> [["ab"]]
irb(main):002:0> "".scan(/\G(?=.)((?>\\.|[^\|])*)(?:\||$)/)
=> []
irb(main):003:0> "".scan(/\G((?>\\.|[^\|])*)(?:\||$)/)
=> [[""]]
...weil man einige Sonderfälle abfragen muss.

Gibt es in der Python-Welt zu diesem Verhalten Docs, Diskussionen, ...?

Es wäre interessant herauszufinden, ob es eventuell andere Nebenwirkungen bei der Python-Lösung gibt. Wenn nicht, sollte man das mal schnell bei comp.lang.ruby oder unter ruby-core einbringen.

_________________
WoNáDo.set_state!(:retired)


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 30 Sep 2007, 15:54 
Offline
Geselle
Benutzeravatar

Registriert: 09 Aug 2006, 11:49
Beiträge: 148
Ich komm da jetzt nochmal drauf zurück, weil ich momentan zusammen mit Georg Brandl an einem Python Wrapper für Oniguruma arbeite.

Da bin ich jetzt nochmal über das Problem gestoßen. Die Engine hat damit gar nichts zu tun, Oniguruma macht kein String Escaping, das ist dem Implementor selber überlassen. Und dabei hat man vier Möglichkeiten:
1.) Kein Positionscheck, die Engine stirbt in einer Endlosschleife
2.) Positionscheck nach Match, das macht Ruby. Man bekommt bei einer Re, die eben auch Null Strings matcht genau einen ersetzten String zu viel.
3.) Positionscheck vor dem Match. Wenn dann der Match einen Leerstring gematcht hat bricht man ab.
4.) Gleich wie drei, aber matcht man mindestens einmal. (Das macht sre)

Meiner Meinung nach ist 4. das brauchbarste, weil du Empty Matches nicht extra behandeln musst. Ich bin schwer dafür, dass auch in Ruby so zu implementieren.

_________________
[code=]class<<self;define_method(%_>6E9@50>:DD:?8_.tr(%_0-f_,%_\_-t_)){|*_|@_\
=_};end;(Just another Ruby hacker!);(_,@_=@_;$><<_<<%_ _)while@_;$><<$/[/code]


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 30 Sep 2007, 16:12 
Offline
Interpreter

Registriert: 15 Mär 2005, 19:26
Beiträge: 6142
Wohnort: Karlsruhe
Trag das mal zur Diskussion in comp.lang.ruby oder über http://www.ruby-forum.com/forum/4 ein.

Nur wenn es dort auf Interesse trifft wird was passieren - das kann dann allerdings sehr schnell gehen. Momentan habe ich aber eher den Eindruck, dass die Kerntruppe von Ruby mit der Vorbereitung auf Ruby 1.9.1 beschäftigt ist, so dass mit kurzfristigen Änderungen nicht unbedingt zu rechnen ist.

_________________
WoNáDo.set_state!(:retired)


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 12 Dez 2007, 20:17 
Offline
Interpreter

Registriert: 15 Mär 2005, 19:26
Beiträge: 6142
Wohnort: Karlsruhe
blackbird hat geschrieben:
Ich komm da jetzt nochmal drauf zurück, weil ich momentan zusammen mit Georg Brandl an einem Python Wrapper für Oniguruma arbeite.

(eilt! ){1000}

Gibts das schon? - Wo? - Welche Besonderheiten? - ...?

>>>>> Edit >>>>>

Zur Erklärung: Ein alter Freund von mir erstellt mit Python aus den Quellen (etc.) mathematischer Veröffentlichungen Verweislisten im TeX-Format und setzt dabei auch Reguläre Ausdrücke ein. Er könnte für bestimmte Teile seiner Arbeit meine rekursiven Muster für Klammergebirge (siehe Reguläre Ausdrücke, Teil 5: Benannte Gruppen, Palindrome, Taschenrechner und Klammergebirge.) sehr gut gebrauchen. Da diese aber Oniguruma benötigen suche ich eine Python-Anbindung für diese RegEx-Maschine.

_________________
WoNáDo.set_state!(:retired)


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 15 Dez 2007, 23:35 
Offline
Geselle
Benutzeravatar

Registriert: 09 Aug 2006, 11:49
Beiträge: 148
Ponyguruma gibts im Sandkasten: http://sandbox.pocoo.org/

_________________
[code=]class<<self;define_method(%_>6E9@50>:DD:?8_.tr(%_0-f_,%_\_-t_)){|*_|@_\
=_};end;(Just another Ruby hacker!);(_,@_=@_;$><<_<<%_ _)while@_;$><<$/[/code]


Nach oben
 Profil  
 
 Betreff des Beitrags:
BeitragVerfasst: 16 Dez 2007, 01:25 
Offline
Interpreter

Registriert: 15 Mär 2005, 19:26
Beiträge: 6142
Wohnort: Karlsruhe
blackbird hat geschrieben:
Ponyguruma gibts im Sandkasten: http://sandbox.pocoo.org/

Danke - habe es schon geholt, bin nur leider noch nicht dazu gekommen etwas damit zu machen. Vielen Dank noch mal.

_________________
WoNáDo.set_state!(:retired)


Nach oben
 Profil  
 
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 

Alle Zeiten sind UTC + 1 Stunde [ Sommerzeit ]


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach: