Schrift
[thread]11341[/thread]

qr// Regex Problem

Tags: Ähnliche Threads

Leser: 4


<< >> 9 Einträge, 1 Seite
MatthiasW
 2008-02-21 19:49
#106194 #106194
User since
2008-01-27
367 Artikel
BenutzerIn
[default_avatar]
Hallo,

ich versuche jeweils am Anfang eines Strings folgendes Muster zu matchen:
- doppelte oder einfache Anführungszeichen
- irgendwelche Zeichen, ein backslash escaped das darauf folgende zeichen
- die zu anfang verwendeten anführungszeichen

Mir fällt es leider schwer, das in einem regulären Ausdruck zu schreiben, mein Versuch ist folgender:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
my $rx = qr/
(["']) # save " or ' in $1
(?: # group
[\\]{2} # double escape
| # OR
[\\]$1 # escaped end of data
| # OR
[\\][a-z] # escaped letter ( escape sequence )
| # OR
[^\\\n\r$1] # other useable characters
) * # end group, any times
$1 # content of $1
/x;

# ...später dann...

$string =~ /^($rx)/;

Wenn ich den Code laufen lasse, passiert folgendes:
Ich bekomme 3 mal die "Use of uninitialized value..." Warnung, dass führe ich auf die 3 $1 zurück. Weiterhin funktioniert die regex nicht wie erwartet, sie matcht zu viel ( das hängt wohl mit den uninitialisierten Werten zusammen ).

Folgende regex funktioniert übrigens prima, beschränkt jedoch die Wahl der Anführungszeichen:
Code: (dl )
my $rx = qr/" (?: [\\]{2} | [\\]" | [\\][a-z] | [^\\"\n\r] ) * "/x;

Ich freue mich schon auf Anregungen!

MfG
perl -E'*==*",s;;%ENV=~m,..$,,$&+42;e,$==f;$"++for+ab..an;@"=qw,u t,,print+chr;sub f{split}say"@{=} me"'
pq
 2008-02-21 20:01
#106196 #106196
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
innerhalb der regex kannst du nicht auf $1 zugreifen, dort musst du \1 schreiben.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
MatthiasW
 2008-02-22 00:24
#106208 #106208
User since
2008-01-27
367 Artikel
BenutzerIn
[default_avatar]
Das hatte ich vergessen dazuzuschreiben, wenn ich alle $1 durch \1 ersetze bekomme ich zwar keine Warnungen mehr, aber die regex matcht gar nichts mehr :(

Das liegt warscheinlich an der character class, aber ich weiß nicht, wie ich die umschreiben soll...
Code: (dl )
[^\\\n\r\1]


MfG
perl -E'*==*",s;;%ENV=~m,..$,,$&+42;e,$==f;$"++for+ab..an;@"=qw,u t,,print+chr;sub f{split}say"@{=} me"'
renee
 2008-02-22 09:28
#106217 #106217
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Welche Strings sollen denn gematcht werden?
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/
pq
 2008-02-22 10:05
#106221 #106221
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
MatthiasW+2008-02-21 23:24:01--
Das hatte ich vergessen dazuzuschreiben, wenn ich alle $1 durch \1 ersetze bekomme ich zwar keine Warnungen mehr, aber die regex matcht gar nichts mehr :(

Das liegt warscheinlich an der character class, aber ich weiß nicht, wie ich die umschreiben soll...
Code: (dl )
[^\\\n\r\1]

naja, erstmal: wenn du schon wusstest, dass du \1 benutzen musst, wieso hast du dann $1
genommen?
desweiteren: \1 in einer character class scheint so nicht zu gehen, aber das hindert uns ja nicht
daran, es zum funktionieren zu bringen. eine character class kann man ja auch umschreiben:
Code: (dl )
(?:[^\\\n\r]|\1)

da ich keine ahnung habe, wie deine beispielstrings aussehen, musst du halt jetzt mal rumprobieren.
bei dir ist es eine negierte klasse, was heisst, dass es noch etwas komplizierter wird.
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
betterworld
 2008-02-22 14:01
#106242 #106242
User since
2003-08-21
2613 Artikel
ModeratorIn

user image
pq+2008-02-22 09:05:16--
Code: (dl )
(?:[^\\\n\r]|\1)

Das macht jetzt aber etwas anderes. Er wollte ja ein Zeichen, was *nicht* \1 ist, und diese Negierung ging Dir verloren. Man muesste einen Look-Ahead nehmen, etwa so:

Code: (dl )
(?!\1)[^\\\n\r]


Aber irgendwie kommt mir das alles zu kompliziert vor. Warum moechtest Du denn eigentlich, dass ' \' ' matcht, " \' " aber nicht?
MatthiasW
 2008-02-24 03:12
#106308 #106308
User since
2008-01-27
367 Artikel
BenutzerIn
[default_avatar]
Ersteinmal Danke für die Antworten.

Die Strings die gematcht werden sollen sehen folgendermaßen aus ( nein, ich versuche nicht Perl zu parsen ) :
Code: (dl )
"Test", 'test mit \' und \", aber auch "', "\a\b\c .. \z", '\\ Test'

Die Strings sollen allerdings keine echten Zeilenumbrüche enthalten.

@pg: ich wusste nicht ob ich $1 oder \1 verwenden muss, habe mich dann für $1 entschieden, weil ich es so von s/// gewöhnt bin.

@betterworld: Daran hatte ich nicht gedacht, es soll beides matchen, aber das hat ja nichts mit der Zeichenklasse zu tun, sie soll nur verhindern, dass das schließende Anführungszeichen, oder ein Zeilenumbruch, oder ein nicht zugelassener Backslash ( erscheint mir im Nachhinein unnötig ) verwendet wird.

Deine angegebene Regex ( '(?!\1)[^\\\n\r]' ) funktioniert leider nicht.
Weiterhin habe ich auch (?!(?:\1|[\\\n\r])) ausprobiert, auch ohne Erfolg.

Ich hoffe Ihr könnt mir helfen, probiere das nun schon etwas länger hinzubekommen :(

MfG
perl -E'*==*",s;;%ENV=~m,..$,,$&+42;e,$==f;$"++for+ab..an;@"=qw,u t,,print+chr;sub f{split}say"@{=} me"'
murphy
 2008-02-24 04:34
#106309 #106309
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Bei mir scheint dieser Regex zu funktionieren: qr/(["'])(?:\\[\\"'a-z]|[^\\"'\r\n]|(?!\1)["'])*\1/
When C++ is your hammer, every problem looks like your thumb.
MatthiasW
 2008-02-25 19:19
#106334 #106334
User since
2008-01-27
367 Artikel
BenutzerIn
[default_avatar]
Ah! Mir ist gerade etwas aufgefallen.

Ich habe folgendes Testskript:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/perl

use strict;
use warnings;

my $rx = qr/(["'])(?:\\[\\"'a-z]|[^\\"'\r\n]|(?!\1)["'])*\1/;

do {
print $_ =~ /^($rx)/ ? "'$_' matcht: $1"
: "'$_' matcht nicht!";
<>;
} foreach (
q("\\\\\\"\\n\\a"),
q("test"),
q("Ein 2ter Test..."),
q("Test mit:)."\n\"",
);

<>;

__END__

Dieses Skript liefert mir nun immer die Ausgabe ... matcht nicht!. Der regex den ich vorher verwendet habe, hatte selbst keinen geklammerten Ausdruck, da er nicht beide Sorten von Anführungszeichen unterstützen musste. Daher gab es dabei auch keine Probleme.
Der neue regex muss nun aber wissen, welches Zeichen am Anfang steht, damit er das Ende des Strings erkennen kann.
Da ich aber innerhalb der Schleife auch Klammern um den eigentlichen regex setze, wird $1 belegt.
Lasse ich die Klammern im regex innerhalb der Schleife weg, bekomme ich die Ausgabe ... matcht: '"'.

Meine aktuelle Lösung ist jetzt: Ich benutze keine Klammern beim matchen und ersetze $1 in der Ausgabe mit $&.
Kann man das noch geschickter/schöner lösen?

MfG
perl -E'*==*",s;;%ENV=~m,..$,,$&+42;e,$==f;$"++for+ab..an;@"=qw,u t,,print+chr;sub f{split}say"@{=} me"'
<< >> 9 Einträge, 1 Seite



View all threads created 2008-02-21 19:49.