Schrift
[thread]6137[/thread]

Reguläre Ausdrücke vorkompilieren: (Wie bekomme ich Parameter ans qr//?)

Leser: 1


<< |< 1 2 >| >> 14 Einträge, 2 Seiten
Crian
 2004-03-12 14:46
#80903 #80903
User since
2003-08-04
5870 Artikel
ModeratorIn
[Homepage]
user image
Ich habe ein Programm, dass aus einer Datei >1000 roh vorformulierte reguläre Ausdrücke ausliest, diese verfeinert und dann auf jeden Datensatz einer anderen Datei anwendet.

Die Urversion eines nicht Perl-vertrauten Kollegen führte jeden dieser regulären Audrücke in jedem Datensatz erneut aus, wodurch das Programm irre langsam wird (etwa 6h für ca 600k Datensätze).

Ich habe dann eine Version geschrieben, die im BEGIN-Block ein Modul schreibt, in dem eine Funktion enthalten ist, die diese ganzen regulären Ausdrücke durchtestet. Danach wird dieses Modul dann mit use eingebunden und die Funktion verwendet. Das funktioniert auch wunderbar, und es braucht jetzt 10 Minuten statt 6 Stunden. So weit so gut.

Dann erinnerte ich mich daran, dass es den vorkompilierungs-Operator qr// gibt. Also dachte ich mir, ich könnte mir das Erzeugen einer externen Moduldatei vielleicht sparen und einfach die vorkompilierten regulären Ausdrücke in meinem AoH ablegen.

Das Problem ist, dass die produzierten verfeinerten RE's schon die Form

Code: (dl )
m~REGULAERERAUSDRUCK~ig


haben. Nagut, also dachte ich mir, schneide ich doch einfach mit

Code: (dl )
	my ($qr, $mod) = $re =~ m#^m~(.*)~(.*)$#;


(dabei enthält $re den obigen regulären Ausdruck) den eigentlichen Ausdruck und seine Parameter in zwei Variablen aus.

jetzt ist die Frage, wie bekomme ich die Parameter an den qr-Teil drangeklebt? Auf die naive Weise

Code: (dl )
		     re     => qr~$re~$mod,


klappt es nicht (was mich auch nicht sehr wundert). Die Frage ist jetzt, wie mache ich es dann?

Im Perl Kochbuch gibt es auch ein Kapitel zu diesem Thema habe ich gesehen, bei mir Abschnitt 6.10. Interpolierte Matches beschleunigen (S. 191). Da ist meine Modul-erzeugungsvariante gar nicht dabei, dafür einige andere nette Methoden. Die möchte ich aber eigentlich gar nicht mehr heranziehen, ich habe ja schon eine funktionierende Methode, mich würde nur mal theoretisch interessieren, wie und ob es mit qr geht (und dann auch praktisch, wie schnell es im Vergleich zu meiner Methode ist).

Mir fällt gerade ein, vielleicht geht es über
Code: (dl )
(?[Modifikator]:Muster)


also so:

Code: (dl )
		     re     => qr~(?$mod:$re)~,


?

Das probiere ich gleich mal aus ...

... ja das schluckt er, aber die regulären Ausdrücke erzeugen kein Match... hmmmm irgendwas past da noch nicht.
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
 2004-03-12 14:50
#80904 #80904
User since
2003-08-04
5870 Artikel
ModeratorIn
[Homepage]
user image
Dummer Fehler... so gehts:

Code: (dl )
re     => qr~(?$mod:$qr)~,


(Oben hatte ich noch $re statt $qr eingesetzt, dadurch sucht er nach Tilden etc. die er natürlich nicht findet.)
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
 2004-03-12 14:56
#80905 #80905
User since
2003-08-04
5870 Artikel
ModeratorIn
[Homepage]
user image
Allerdings ist die neue Methode langsamer als meine erste... sie braucht auf 22k Datensätzen 42 Sekunden im Gegensatz zu 19 Sekunden der ersten.

Naja, im Vergleich zur Ursprünglichen Variante ist das natürlich immer noch rasant schnell, aber dann bleib ich wohl lieber bei der Modul-ausgebenden-Variante.

Ich werd gleich nochmal einen Vergleich auf einer größeren Menge fahren...
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
ptk
 2004-03-12 15:03
#80906 #80906
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Eine statische oder mit /o kompilierte variable Regexp ist schneller als eine qr//-Regexp. (Habe ich mal gebenchmarkt...)
pq
 2004-03-12 15:04
#80907 #80907
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
je nach den umständen hilft auch noch ein /o, also qr(...)o.
dazu müsste man aber mal ein bisschen code sehen.
ach ja, und vielleicht hilft study?
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
Crian
 2004-03-12 16:54
#80908 #80908
User since
2003-08-04
5870 Artikel
ModeratorIn
[Homepage]
user image
Hmmm interessant... hier erst nochmal die Ergebnisse des lägeren Laufes:

via Modul: 580.939 Datensaetze, Zeit: 00:08:04
mit qr//: 580.939 Datensaetze, Zeit: 00:17:36

Mehr Code? Für welchen Fall möchtest Du denn mehr Code sehen? Die Variante mit o probiere ich mal eben aus, wobei mir nicht wirklich einleuchtet, wieso er beim vorkompilieren diesen Schalter nich braucht, was kann sich denn dann noch ändern?
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
 2004-03-12 17:43
#80909 #80909
User since
2003-08-04
5870 Artikel
ModeratorIn
[Homepage]
user image
Ich poste mal die Funktion, die das AoH aufbaut. Die Funktion modify() verfeinert die eingelesene RE und gibt etwas in der ganz oben im ersten Post geschilderten Form zurück.

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
31
32
33
34
35
36
37
38
39
40
sub create_aoh ($) {
# -----------------------------------------------------------------------------
# sub          : c r e a t e _ a o h
# -----------------------------------------------------------------------------
# Autor        : CD
# Aufgabe      : WZ-Liste in AoH übernehmen
# Parameter    : Name der Listendatei
# Rückgabewert : Eingelesenes AoH
# -----------------------------------------------------------------------------
# 0.0.1 - 12.03.2004 - CD - Erstellt
# -----------------------------------------------------------------------------

   my $file = shift;
   my @wz   = ();


   open (LST, $file) or die "Kann Datei '$file' nicht zum Lesen oeffnen: $!";

   while (<LST>) {
       next if m~^\s*$~; # Leerzeilen überspringen
       my ($id, $code, $vor_re) = split /\t/;
       unless (defined $vor_re) {
           warn "Fehler in Listendatei Zeile $. '$_'";
           next;
       }
       my $re = modify($vor_re);
       my ($qr, $mod) = $re =~ m#^m~(.*)~(.*)$#;
       push  @wz, {
                    id     => $id,
                    wzcode => $code,
                    re     => qr~(?$mod:$qr)o~,
                  };

   }

   close LST or warn $!;

   return @wz;

} # sub create_aoh


später wird das erstellte Array (AoH) in der Funktion wzcode wie folgt verwendet:

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
sub wzcode ($$) {
# -----------------------------------------------------------------------------
# sub          : wzcode
# -----------------------------------------------------------------------------
# Autor        : CD
# Aufgabe      : Vergabe des WZ-Codes
# Parameter    : 1) Begriff
#                2) Referenz auf wz-AoH
# Rückgabewert : gefundene Zahl oder 00000
# -----------------------------------------------------------------------------
# 0.0.1 - 12.03.2004 - CD - Erstellt
# -----------------------------------------------------------------------------

   my $begriff = shift;
   my $refwz   = shift;
   my $ret     = '00000';


   for (@$refwz) {
       if ($begriff =~ $_->{re}) {
           $ret = $_->{wzcode};
   last;
       }
   }


   return $ret;

} # sub wzcode


Diese wiederum wird in der Schleife aufgerufen, die die Datendatei einliest. In jeder Zeile werden dann zu bestimmten Daten mit dieser Funktion die wzcodes zurückgegeben, wenn der entsprechende reguläre Ausdruck passt.


Edit: Hmmm für pq hätte ich jetzt das = () besser wegnehmen sollen ;)\n\n

<!--EDIT|Crian|1079106717-->
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
 2004-03-12 18:14
#80910 #80910
User since
2003-08-04
5870 Artikel
ModeratorIn
[Homepage]
user image
So... der Test der Variante mit o ist durch, dauert interessanter Weise länger als ohne:

via Modul: 580.939 Datensaetze, Zeit: 00:08:04
mit qr//:  580.939 Datensaetze, Zeit: 00:17:36
mit qr//o:  580.939 Datensaetze, Zeit: 00:27:48


Edit: da ich gleich Feierabend mache und erst Montag in einer Woche weiterarbeite ist es nicht dringend. Ich gebe jetzt die Modulvariante weiter, Geschwindigkeit rult. Aber vielleicht gehe ich den anderen Varianten übernächste Woche nochmal weiter nach...\n\n

<!--EDIT|Crian|1079108154-->
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
ptk
 2004-03-12 18:50
#80911 #80911
User since
2003-11-28
3645 Artikel
ModeratorIn
[default_avatar]
Hmmm. Ich dachte eigentlich auch an /o ohne qr.
Strat
 2004-03-13 12:04
#80912 #80912
User since
2003-08-04
5246 Artikel
ModeratorIn
[Homepage] [default_avatar]
/o bringt eigentlich nur was, wenn das Pattern wiederholt (z.B. in einer Schleife ueber alle Zeilen) vorkommt und im Pattern $Variablen vorkommen. ich vermute auch, dass dir da study mehr bringen koennte... das braucht zwar selbst ein wenig zeit, aber gerade wenn du viele REs ueber ein Muster laufen laesst, ist diese Zeit oft schnell wieder eingeholt und mehr...

hmmm, da war pq wieder schneller...
perl -le "s::*erlco'unaty.'.dk':e,y;*kn:ai;penmic;;print"
http://www.fabiani.net/
<< |< 1 2 >| >> 14 Einträge, 2 Seiten



View all threads created 2004-03-12 14:46.