[megoldva] Perl csere optimalizálás

Egy nagy fájlban cseréket végzek, melyek egymást kizáró cserélendő karakterláncokat tartalmaznak. PERL megoldás pl:
s/EZT:50048/ERRE/;
s/EZT:50049/EMERRE/;
s/EZT:50050/AMARRA/;
...
Nagy feldolgozandó fájl esetén igen lassú a futás. Lehet valahogy tudatni a PERL-lel, hogy ezek az alternatívák "elseif"-ként kapcsolódnak egymáshoz? Tehát, ha már egy vizsgált sorban talált egy illeszkedést, akkor nem kell a többit megnézni? Jó volna, ha ez nem tenné lehetetlenné az áttekintést (így milliónyi egymásba ágyazott if nem jó).

Hozzászólások

Ha sebesség kell, írd meg flex-ben:

pld.flex:

%%
EZT:50048 printf("ERRE");
EZT:50049 printf("EMERRE");
.
.
.

A te megoldásod azért lassú, mert minden alkalommal, amikor szerepel az s/// kifejezés, akkor a Perlnek inicializálni kell a regexp-feldolgozót.

Ha a mit-mire párok egyszerű sztatikus sztringek, akkor tárolhatod őket egy hash-ben, és egyetlen regexp-illesztéssel elvégezheted a cserét.


BEGIN{
my %csere = (
    "EZT:50048" => "ERRE",
    "EZT:50049" => "EMERRE",
    "EZT:50050" => "AMARRA",
)

my $regexp_string = join "|", sort keys %csere;
my $regexp = qr/$regexp_string/;
}

# ez fut le minden sorra
s/$regexp/$csere{$1}/;

Lehet, hogy még hatékonyabban meg lehet csinálni.
Ha a "mit" sztringek között van olyan, amelyik egy másiknak része, az bekavarhat.

Így remek!

Álljon itt egy összehasonlító mérés.

A feldolgozott 106 MB-os fájl 1533691 sorból, a feldolgozás 3100 cseréből állt.

Az eredeti (csak s///-eket tartalmazó) szkript:
time ./test1

real 45m8.003s
user 44m38.479s
sys 0m3.352s

Kikuchiyo villámgyors megoldásával mindez néhány másodperc:
time ./test2

real 0m6.656s
user 0m2.932s
sys 0m0.464s

Nálam semmi különbség a két megoldás futási ideje között.

Egyszerű megoldás:


#!/usr/bin/perl -pw

s/0:30/ERRExxx/;
s/0:40/EMERRExxx/;
s/0:50/AMARRAxxx/;

-------------------------

"Bonyolult" megoldás:


#!/usr/bin/perl -pw

BEGIN{
  %csere = (
          "0:30" => "ERRExxx",
          "0:40" => "EMERRExxx",
          "0:50" => "AMARRAxxx",
  );

  $regexp_string = join "|", sort keys %csere;
  $regexp = qr/($regexp_string)/;
}

# ez fut le minden sorra
s/$regexp/$csere{$1}/;

-----------------

Az input file mérete ~242MB, 864000 sorral, melyben ~10000 helyettesítés történik összesen.
Perl verzio: 5.10.1

A futási idő mindkét esetben ~1.5sec.

Két fogalom keveredhet itt: a bekövetkező Helyettesítések száma (legyen H) és a csereKifejezések száma (legyen K).
Nálam a K volt 3100 (azaz s/// sorokból volt egymás alatt 3100); a H az ki tudja, mennyi - akár sok százezres nagyságrendű is lehet, mert némelyik cserekifejezés többször is alkalmazásra került. A "sornyi"-n tehát K-t értettem (és szerintem te H-t).

Köszi minden segítséget - a flex teljesen új számomra, utána kell nézzek a szintaktikának (hogy hogy eresztem rá egy fájlra); a perl optimalizálásért is igen hálás vagyok!! :-)