Passende Regex?

Passende Regex?

am 14.08.2007 19:03:24 von Ferry Bolhar

Hallo,

ich muss einen String in der Form

a=b,c=d,e=f,...

durchwassern, wobei (hier) auch Werte fehlen können,
also z.B.

a=,c=d,e=,...

Die Werte sollen dann einem Hash zugewiesen werden.
Aber das ist noch nicht das Problem. Mit

my $str = '...'; # Enthält den String
my %hash;

$hash{$1} = $2 while $str =~ /([^=]+)=([^,]+)?,?/g;

sollte das ja klappen.

Das Problem ist, dass alle Werte auch die hier zur Trennung
verwendeten Zeichen "=" und "," enthalten können, diese
sind dann mit einem "~" gekennzeichnet (ein "~~" wird für
ein literales "~" verwendet; ähnlich also dem Backslash in
Perl). Der Ausdruck

a~==b~,~~c

sollte also demnach als

$hash{a=} = 'b,~c';

verwertet werden.

Wie mache ich das? Ich habe es schon mit negativem
Look-Behind:

/([^=]+(?
probiert, aber das klappt nicht - ich bekomme falsche
Werte zurück. Wobei hier die Regel mit der doppelten
Tilde noch gar nicht berücksichtigt ist.

Ist das alles überhaupt innerhalb einer Regex machbar?

LG, Ferry
--

Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at

Re: Passende Regex?

am 14.08.2007 19:26:33 von Moritz Lenz

Hallo,

Ferry Bolhar wrote:
> Hallo,
>=20
> ich muss einen String in der Form
>=20
> a=3Db,c=3Dd,e=3Df,...
>=20
> durchwassern, wobei (hier) auch Werte fehlen können,
> also z.B.
>=20
> a=3D,c=3Dd,e=3D,...
>=20
> Die Werte sollen dann einem Hash zugewiesen werden.
> Aber das ist noch nicht das Problem.=20

Also
my %hash =3D map { # hier string zerlegen } split m/,/, $string
right?

> Mit
>=20
> my $str =3D '...'; # Enthält den String
> my %hash;
>=20
> $hash{$1} =3D $2 while $str =3D~ /([^=3D]+)=3D([^,]+)?,?/g;
>=20
> sollte das ja klappen.

Machs dir nicht schwerer als es ist - nimm split.

> Das Problem ist, dass alle Werte auch die hier zur Trennung
> verwendeten Zeichen "=3D" und "," enthalten können, diese
> sind dann mit einem "~" gekennzeichnet (ein "~~" wird für
> ein literales "~" verwendet; ähnlich also dem Backslash in
> Perl). Der Ausdruck

d.h du splittest an =3D, das nicht hinter ~ steht.
Also
split m/(?
Alles in allem
my @elems =3D split m/,/, $string;
my %hash;
for (@elems){
my ($key, $val) =3D split m/(? $hash{$key} =3D $val;
}

(Wie ich zugeben muss ungetestet, also sei umso beeindruckter, wenn es
auf Anhieb funktioniert ;-)

Moritz

--=20
Moritz Lenz
http://perl-6.de/ http://moritz.faui2k3.org/

Re: Passende Regex?

am 14.08.2007 20:29:21 von Mirco Wahab

Ferry Bolhar wrote:
> a=b,c=d,e=f,...
> durchwassern, wobei (hier) auch Werte fehlen können,
> also z.B.
> a=,c=d,e=,...
> Die Werte sollen dann einem Hash zugewiesen werden.
> Aber das ist noch nicht das Problem. Mit
> Das Problem ist, dass alle Werte auch die hier zur Trennung
> verwendeten Zeichen "=" und "," enthalten können, diese
> sind dann mit einem "~" gekennzeichnet (ein "~~" wird für
> ein literales "~" verwendet; ähnlich also dem Backslash in
> Perl). Der Ausdruck
> a~==b~,~~c
> sollte also demnach als
> $hash{a=} = 'b,~c';
> verwertet werden.
> Wie mache ich das? Ich habe es schon mit negativem

Warum nicht eine triviale Lösung
(alles so hinschreiben wie Du es
gesagt hast?), z.B.:

....
my $rg = qr{
( (?:\w | ~= | ~~)+ ) # $1
= # =
( (?:\w | ~, | ~~)* ) # $2 (?)
,? #, | $
}x; #

my %stuff;

$stuff{$1} = $2 while $string =~ /$rg/g;
....

Die Tildmaskierungen musst Du allerdings
später behandeln, das geht nicht mit
simplem Regex (aber mit dynamic execution
assertion).

Viele Grüße

Mirco

Re: Passende Regex?

am 14.08.2007 20:31:05 von Mirco Wahab

Mirco Wahab wrote:
> ( (?:\w | ~= | ~~)+ ) # $1
> = # =
> ( (?:\w | ~, | ~~)* ) # $2 (?)
>

Uups, der part lässt sich natürlich
"vereinheitlichen":

( (?:\w | ~[=~,])+ ) # $1
= # =
( (?:\w | ~[=~,])* ) # $2 (?)

Viele Grüße

M.

Re: Passende Regex?

am 14.08.2007 21:07:26 von Frank Seitz

Moritz Lenz wrote:

> d.h du splittest an =, das nicht hinter ~ steht.

Gegenbeispiel: a~~=b

Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel

Re: Passende Regex?

am 14.08.2007 21:35:42 von Moritz Lenz

Hallo,

Frank Seitz wrote:
> Moritz Lenz wrote:
>=20
>> d.h du splittest an =3D, das nicht hinter ~ steht.
>=20
> Gegenbeispiel: a~~=3Db

Stimmt, daran habe ich nicht gedacht. Und dann geht auch das splitten an
dem Komma nicht.

D.h. man probiert erst mal nach allem zu suchen, was kein Delimiter ist
(für den ersten Schritt, also an unescapetem Komma splitten), und dabei=

den String abbauen
s{
\A
((?:
[^,~] # "normale" Zeichen
|
(?: \~.) # oder Tilde, die etwas escaped
)+)
}{}smx

Den abgebauten Teilstring hat man dann in $1, was man auf eine @liste
pushen kann. Das nächste Zeichen ist dann ein Komma (oder eine Tilde,
falls es das letzte Zeichen im String ist), das man entfernen muss.

Dann kann man den gleichen Trick wieder zum spalten am =3D verwenden:

s{
\A
((?:
[^=3D~]
|
(?: \~.)
)+)
}{}smx


Wenn man den String nicht abbauen will, kann man auch
m{\G $vorherige_regex | \, }smxg nehmen - ist vermutlich effizienter.

HTH,
Moritz

--=20
Moritz Lenz
http://perl-6.de/ http://moritz.faui2k3.org/

Re: Passende Regex?

am 16.08.2007 12:37:19 von Ferry Bolhar

Mirco Wahab:

> Warum nicht eine triviale Lösung

Ja, warum eigentlich nicht? Vielleicht, weil ich mich
darauf versteift hatte, das mit negativen Look-Behind
lösen zu müssen? ;-))

Danke, Mirco! Das haut jetzt hin.

Danke aber auch an alle anderen, die sich für mich
den Kopf zerbrochen haben.

> Die Tildmaskierungen musst Du allerdings
> später behandeln,

Das sollte ja wohl nicht allzu schwierig sein...

> das geht nicht mit simplem Regex
> (aber mit dynamic execution assertion).

Womit, bitte?

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at