Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]12248[/thread]

Capturing und $1

Leser: 1


<< |< 1 2 >| >> 18 Einträge, 2 Seiten
defun
 2008-07-25 02:38
#112670 #112670
User since
2008-07-18
28 Artikel
BenutzerIn
[default_avatar]
Ich habe jetzt insgesamt mindestens einen Tag damit zugebracht, einen Fehler zu finden, der wirklich einen mini-winzigen Auslöser hatte. Der Fehler war folgender Natur:

Wenn ich vor ein Stück Code einen Regex wie
Code (perl): (dl )
'f' =~ m/(.)/;

gestellt habe, produzierte er einen Fehler (keinen Perl-Fehler, sondern einen von mir definierten). Sobald der Regex weggelassen wurde, bzw. der Regex keine Capturing-Klammern mehr enthielt, lief der Code fehlerfrei. Um den Fehler so weit einzugrenzen, habe ich natürlich allein schon Stunden gebraucht. Fazit: Die Tatsache, dass $1 gesetzt war, führte zu einem sehr schwer findbaren Fehler, den ich noch nicht beschreiben möchte.

Dieser Thread soll nun dazu dienen, mir zu zeigen, ob ich einfach zu dämlich war, oder ob auch DU über die Falle gestolpert wärst, die in meinem Code verborgen war. Daher meine Frage:

Wenn du einen Regex mit Capture-Klammern hast, von dem du weißt, dass er ausgeführt wird -- bist du dir dann sicher, dass ein $1 direkt hinter diesem Regex (also z.B. in der nächsten Zeile und im gleichen Kontext) entweder einen neuen Wert bekommt, oder auf undef gesetzt wird? Oder anders gefragt: Fällt dir irgendein Weg ein, das Setzen von $1 zu vermeiden?

Wenn es ein paar Antworten gibt, "löse ich das Rätsel auf", falls es dann noch nötig ist.

Ich habe mit Perl 5.8.8 gearbeitet, wie es mit anderen Versionen aussieht, kann ich gerade nicht ausprobieren.
moritz
 2008-07-25 02:46
#112671 #112671
User since
2007-05-11
923 Artikel
HausmeisterIn
[Homepage]
user image
Ich habe keine Ahnung worauf du hinaus willst, aber in perlre steht:

Quote
NOTE: failed matches in Perl do not reset the match variables, which makes it easier to write
code that tests for a series of more specific cases and remembers the best match.


Meinst du das?

Capture-Variablen zu benutzen ohne vorher zu überprüfen ob die Regex überhaupt gemacht hat ist fast immer ein Fehler
LanX-
 2008-07-25 02:55
#112672 #112672
User since
2008-07-15
1000 Artikel
BenutzerIn

user image
ähm ...
Code (perl): (dl )
print $1 if ('f' =~ m/(.)/) 


Das Hauptprodukt des Matchingoperators ist ein Wahrheitswert, $1 ist nur ein (eventuelles) Nebenprodukt, wenn überhaupt geklammert wurde. Du solltest den 2. nicht vor dem 1. schritt machen.

Quote
Dieser Thread soll nun dazu dienen, mir zu zeigen, ob ich einfach zu dämlich war, oder ob auch DU über die Falle gestolpert wärst, die in meinem Code verborgen war. Daher meine


ach so.... ; )
LanX-
 2008-07-25 03:12
#112673 #112673
User since
2008-07-15
1000 Artikel
BenutzerIn

user image
defun+2008-07-25 00:38:25--
Fällt dir irgendein Weg ein, das Setzen von $1 zu vermeiden?

Klammern weglassen?

Mir gehts wie Moritz ich bin mir nicht sicher ob ich dein Problem verstehe ...
Gast Gast
 2008-07-25 07:31
#112676 #112676
Code (perl): (dl )
print $b if( $t=$1 and ($b)='f'=~/(.)/ and $1=$t );
??
LanX-
 2008-07-25 14:06
#112699 #112699
User since
2008-07-15
1000 Artikel
BenutzerIn

user image
LanX-+2008-07-25 01:12:34--
Klammern weglassen?


vielleicht brauchst du ja Klammern zum Gruppieren, die aber nicht greifen sollen und sonst implizit $1 setzen? Für "oder"-Konstrukte oder ähnliches ?

Code (perl): (dl )
m/(?:.)/


"This is for clustering, not capturing"
betterworld
 2008-07-25 16:03
#112705 #112705
User since
2003-08-21
2614 Artikel
ModeratorIn

user image
defun+2008-07-25 00:38:25--
Fällt dir irgendein Weg ein, das Setzen von $1 zu vermeiden?

Mit local
defun
 2008-07-25 17:39
#112720 #112720
User since
2008-07-18
28 Artikel
BenutzerIn
[default_avatar]
moritz+2008-07-25 00:46:23--
Quote
NOTE: failed matches in Perl do not reset the match variables, which makes it easier to write
code that tests for a series of more specific cases and remembers the best match.

...
Capture-Variablen zu benutzen ohne vorher zu überprüfen ob die Regex überhaupt gemacht hat ist fast immer ein Fehler

Wahr. Aber wenn ich ein Pattern verwende, das einfach matchen MUSS, z.B. /(\t* *)/, dann sollte ich mir doch sicher sein können, oder? Aber weit gefehlt:

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/perl

use strict;
use warnings;

my $text = '123';
pos $text = 3;
'f' =~ m/(.)/; # $1 befüllen
find() for 1 .. 2; # Mindestens zweimal, um den Fehler zu bekommen...

sub find
{
    $text =~ m/\G(.*)/gc;
    print $1, "\n";
}


Bei meiner Perl-Version verhält sich Perl beim ersten find() noch rational und setzt $1 auf einen leeren String, beim zweiten find() jedoch gibt es frustriert auf und lässt $1 auf 'f'. Das ist scheisse, wenn man einen Parser baut, der die \G-/gc-Methode verwendet, um einen Text Stück für Stück zu vernaschen, aber das Ende eines Strings (pos $string == length $string) nicht gesondert behandelt und einen "verbrauchten" String mehr als einmal antestet. Der Fehler entstand dann dadurch, dass ich $1 als Ergebniswert verwendet habe, obwohl es nicht den Match enthielt. Solange $1 undefiniert war, kam es zu keinem Fehler, aber sobald $1 irgendwo am Anfang des Programms gesetzt wurde, zerstörte der Wert in $1 die Logik des Programms. Eine üble Geschichte.

Richtig, ein Check auf den Rückgabewert des Regex hätte geholfen, aber wozu einen Rückgabewert testen, der per Definition wahr ist (wie ich dachte)? Wieder was gelernt...
LanX-
 2008-07-25 18:09
#112724 #112724
User since
2008-07-15
1000 Artikel
BenutzerIn

user image
defun+2008-07-25 15:39:24--
ist scheisse, wenn man einen Parser baut, der die \G-/gc-Methode verwendet, um einen


... wenn du ein Problem mit der \G-/gc-Methode hast wieso sagst du das nicht dazu und lässt uns rätselraten?

EDIT: welcher Fehler überhaupt? Beim zwoten Aufruf von find() findet kein Match mehr statt, deswegen wird $1 auch nicht mehr gestzt (und implizit local) also greift die globale Variable.

Wenn du einen leeren Match erreichen willst dann nimm lieber ein
@matches= ($text =~ m/pattern/) Konstrukt.
renee
 2008-07-25 19:20
#112728 #112728
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Wenn Du denkst, dass das ein Bug ist, dann melde das doch bitte per perlbug. Entweder das ist ein Bug und dann wird sich vermutlich jemand drum kümmern oder Du bekommst von den Perl 5 Porters eine Antwort warum das kein Bug ist.
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
<< |< 1 2 >| >> 18 Einträge, 2 Seiten



View all threads created 2008-07-25 02:38.