Schrift
[thread]7229[/thread]

Problem im Zusammenhang mit REs: kniffelig



<< >> 10 Einträge, 1 Seite
Crian
 2005-08-25 13:20
#57368 #57368
User since
2003-08-04
5866 Artikel
ModeratorIn
[Homepage]
user image
Hallo,

ich habe ein vielleicht merkwürdig anmutendes Problem im Zusammenhang mit regulären Ausdrücken.
Ich hab auch schon eine Lösung für mein Problem, möchte aber hören, ob es schlaueres gibt.

Zu meinem Problem:
Ich habe in einem Text mehrere gleiche Teile (hier: <<A>>), von denen einige durch Klammern im regulären Ausdruck gefangen werden und einige nicht.
Mein Problem ist, hinterher entscheiden zu müssen, welche dieser Ausdrücke gefangen wurden (etwa per Index oder wie auch immer).

Das Problem klingt so erstmal total blöd, denn wenn die Dinge, die ich da fange gleich sind, warum will ich dann wissen, welches ich da gefangen habe.
Das liegt daran, dass diese Dinge Platzhalter sind für spezielle andere Dinge, die sich unterscheiden können.
In meinem speziellen Fall sind es Datumseinträge (und andere mehrfach vorkommende Dinge) und statt <<A>> steht dort <<date>>.

Hier ein kleines Programm zur Veranschaulichung:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;

my $text = "Vorrede bla bla Anfang <<A>> Teil1 <<A>> Teil2 <<B>> Teil3 <<A>> Ende Nachrede.";
my $re = qr~Anfang <<A>> [^<]+ (<<A>>) [^<]+ (<<B>>) [^<]+ <<A>> Ende~;
print "text : [$text]\n",
"re : [$re]\n";

my @allmatch = $text =~ $re;
my ($m1, $m2, $m3) = ($`, $&, $');

print "allmatch: ", Dumper \@allmatch;
print "m1 : [$m1]\n",
"m2 : [$m2]\n",
"m2 : [$m3]\n";


Ausgabe:

Code: (dl )
1
2
3
4
5
6
7
8
9
text    : [Vorrede bla bla Anfang <<A>> Teil1 <<A>> Teil2 <<B>> Teil3 <<A>> Ende Nachrede.]
re : [(?-xism:Anfang <<A>> [^<]+ (<<A>>) [^<]+ (<<B>>) [^<]+ <<A>> Ende)]
allmatch: $VAR1 = [
'<<A>>',
'<<B>>'
];
m1 : [Vorrede bla bla ]
m2 : [Anfang <<A>> Teil1 <<A>> Teil2 <<B>> Teil3 <<A>> Ende]
m2 : [ Nachrede.]


Die Frage ist also eigentlich: Komme ich irgendwie an die Teile zwischen den gematchten Teilen des regulären Ausdrucks heran? Dann könnte ich nämlich ermitteln, welches <<A>> gefangen wurde.

Meine Lösungsidee sieht so aus: Beim Einsetzen der <<A>>s speichere ich eine eindeutige Nummer mit ab. Dann sähe der Satz z.B. so aus:

Code: (dl )
Vorrede bla bla Anfang <<A#14>> Teil1 <<A#8>> Teil2 <<B#1>> Teil3 <<A#9>> Ende Nachrede.


Und dann würde ich die regulären Ausdrücke, mit denen ich diesen Satz teste (das sind sehr sehr viele und die will ich nicht ändern) automatisch vor dem Einsetzen in qr~~ mit

Code: (dl )
$reausdruckstext =~ s~>>~#\\d+>>~g;


überarbeiten, so dass ich hinterher meine Treffer genau identifiezieren kann.

Daraus ergibt sich dann dieses Progrämmchen:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;

my $text = 'Vorrede bla bla Anfang <<A#14>> Teil1 <<A#8>> Teil2 <<B#1>> Teil3 <<A#9>> Ende Nachrede.';
my $retext = 'Anfang <<A>> [^<]+ (<<A>>) [^<]+ (<<B>>) [^<]+ <<A>> Ende';
print "text : [$text]\n",
"retext : [$retext]\n";

$retext =~ s~>>~#\\d+>>~g;
my $re = qr~$retext~;
print "retext : [$retext]\n",
"re : [$re]\n";

my @allmatch = $text =~ $re;
my ($m1, $m2, $m3) = ($`, $&, $');

print "allmatch: ", Dumper \@allmatch;
print "m1 : [$m1]\n",
"m2 : [$m2]\n",
"m2 : [$m3]\n";


mit der Ausgabe

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
text    : [Vorrede bla bla Anfang <<A#14>> Teil1 <<A#8>> Teil2 <<B#1>> Teil3 <<A#9>> Ende Nachrede.]
retext : [Anfang <<A>> [^<]+ (<<A>>) [^<]+ (<<B>>) [^<]+ <<A>> Ende]
retext : [Anfang <<A#\d+>> [^<]+ (<<A#\d+>>) [^<]+ (<<B#\d+>>) [^<]+ <<A#\d+>> Ende]
re : [(?-xism:Anfang <<A#\d+>> [^<]+ (<<A#\d+>>) [^<]+ (<<B#\d+>>) [^<]+ <<A#\d+>> Ende)]
allmatch: $VAR1 = [
'<<A#8>>',
'<<B#1>>'
];
m1 : [Vorrede bla bla ]
m2 : [Anfang <<A#14>> Teil1 <<A#8>> Teil2 <<B#1>> Teil3 <<A#9>> Ende]
m2 : [ Nachrede.]


Damit wüsste ich hinterher über @allmatch genau, welche der <<A>>s ich gefangen habe.

Gibt es eine einfachere Lösung?
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
Crian
 2005-08-25 13:36
#57369 #57369
User since
2003-08-04
5866 Artikel
ModeratorIn
[Homepage]
user image
Ich hab das Lösungsprogramm nochmal etwas verfeinert:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;

my $text = 'Vorrede bla bla Anfang <<A>> Teil1 <<A>> Teil2 <<B>> Teil3 <<A>> Ende Nachrede.';
my $retext = 'Anfang <<A>> [^<]+ (<<A>>) [^<]+ (<<B>>) [^<]+ <<A>> Ende';
print "Original:\n",
"text : [$text]\n",
"retext : [$retext]\n";

my $magicnumber = 0;
while ($text =~ s~(?<=\D)>>~#$magicnumber>>~) {
++$magicnumber;
}
$retext =~ s~>>~#\\d+>>~g;
my $re = qr~$retext~;
print "\nVeraendert:\n",
"text : [$text]\n",
"retext : [$retext]\n",
"re : [$re]\n";

my @allmatch = $text =~ $re;
my ($m1, $m2, $m3) = ($`, $&, $');

print "\nallmatch: ", Dumper \@allmatch;
print "m1 : [$m1]\n",
"m2 : [$m2]\n",
"m2 : [$m3]\n";


Ausgabe:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Original:
text : [Vorrede bla bla Anfang <<A>> Teil1 <<A>> Teil2 <<B>> Teil3 <<A>> Ende Nachrede.]
retext : [Anfang <<A>> [^<]+ (<<A>>) [^<]+ (<<B>>) [^<]+ <<A>> Ende]

Veraendert:
text : [Vorrede bla bla Anfang <<A#0>> Teil1 <<A#1>> Teil2 <<B#2>> Teil3 <<A#3>> Ende Nachrede.]
retext : [Anfang <<A#\d+>> [^<]+ (<<A#\d+>>) [^<]+ (<<B#\d+>>) [^<]+ <<A#\d+>> Ende]
re : [(?-xism:Anfang <<A#\d+>> [^<]+ (<<A#\d+>>) [^<]+ (<<B#\d+>>) [^<]+ <<A#\d+>> Ende)]

allmatch: $VAR1 = [
'<<A#1>>',
'<<B#2>>'
];
m1 : [Vorrede bla bla ]
m2 : [Anfang <<A#0>> Teil1 <<A#1>> Teil2 <<B#2>> Teil3 <<A#3>> Ende]
m2 : [ Nachrede.]
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
Strat
 2005-08-25 14:01
#57370 #57370
User since
2003-08-04
5246 Artikel
ModeratorIn
[Homepage] [default_avatar]
die variablen $&, $`, $` usw. kennst du schon? (und auch die warnungen ueber deren verwendungen?)
perl -le "s::*erlco'unaty.'.dk':e,y;*kn:ai;penmic;;print"
http://www.fabiani.net/
Crian
 2005-08-25 14:35
#57371 #57371
User since
2003-08-04
5866 Artikel
ModeratorIn
[Homepage]
user image
Ich dachte, das hätte ich durch das Programm klargemacht. Es geht um Teile innerhalb von $&. (Siehe $m1, $m2, $m3 oben.)

Die Problematik kenne ich auch, aber ich komm nicht drum rum. Und wenn man es einmal verwendet im Programm, kann man es überall verwenden...
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
Gast Gast
 2005-08-25 14:46
#57372 #57372
Ich hab's mir nur kurz angesehen, aber bei den Daten würde ich eher zerlegen und eine Struktur zusammenbauen. Es sei denn natürlich, die <<A>> Anordnungen etc. sind fix ;)
Crian
 2005-08-25 15:21
#57373 #57373
User since
2003-08-04
5866 Artikel
ModeratorIn
[Homepage]
user image
Da kann ich mir nicht viel drunter vorstellen.
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
Taulmarill
 2005-08-25 15:39
#57374 #57374
User since
2004-02-19
1750 Artikel
BenutzerIn

user image
ich hab mal ähnliche strukturen parsen müssen, hier ein angepasstes script:
Code: (dl )
1
2
3
4
5
6
  
my $text = 'Vorrede bla bla Anfang <<A>> Teil1 <<A>> Teil2 <<B>> Teil3 <<A>> Ende Nachrede.';
my @parts = split /\s*(<<[^>]+>>)\s*/, $text;

print join "\n", @parts;
print "\n";

das erzeugt dann folgende ausgabe:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
~/test> perl test.pl
Vorrede bla bla Anfang
<<A>>
Teil1
<<A>>
Teil2
<<B>>
Teil3
<<A>>
Ende Nachrede.

hilft dir das weiter?\n\n

<!--EDIT|Strat|1124971219-->
$_=unpack"B*",~pack"H*",$_ and y&1|0& |#&&print"$_\n"for@.=qw BFA2F7C39139F45F78
0A28104594444504400 0A2F107D54447DE7800 0A2110453444450500 73CF1045138445F4800 0
F3EF2044E3D17DE 8A08A0451412411 F3CF207DF41C79E 820A20451412414 83E93C4513D17D2B
Gast Gast
 2005-08-25 15:55
#57375 #57375
So meinte ich's in etwa.
Strat
 2005-08-25 16:00
#57376 #57376
User since
2003-08-04
5246 Artikel
ModeratorIn
[Homepage] [default_avatar]
Code: (dl )
my @parts = split /\s*(<<[^>]+>>)\s*/, $text;

Bei sowas besser
Code: (dl )
<<[^<>]>>
schreiben, sonst faellt es z.B. bei
$string = "<< hallo <<A>> <<<B>>"; oder so eventuell auf die nase
perl -le "s::*erlco'unaty.'.dk':e,y;*kn:ai;penmic;;print"
http://www.fabiani.net/
Crian
 2005-08-25 16:29
#57377 #57377
User since
2003-08-04
5866 Artikel
ModeratorIn
[Homepage]
user image
Ach so, nein, das nützt mir nichts :-)

Wie ich schon schrieb will ich nicht die hunderte von Regeln ändern. Dann verwende ich meine Lösung.
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
<< >> 10 Einträge, 1 Seite



View all threads created 2005-08-25 13:20.