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ó).
- 1225 megtekintés
Hozzászólások
Ha sebesség kell, írd meg flex-ben:
pld.flex:
%%
EZT:50048 printf("ERRE");
EZT:50049 printf("EMERRE");
.
.
.
- A hozzászóláshoz be kell jelentkezni
Ez lett:
$ flex doit.lex
flex: input rules are too complicated (>= 32000 NFA states)
$ wc -l doit.lex
3128 doit.lex
- A hozzászóláshoz be kell jelentkezni
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.
- A hozzászóláshoz be kell jelentkezni
Nincs olyan köztük, ami egymás része lenne (úgyhogy a fenti példa sántít). Köszi!
- A hozzászóláshoz be kell jelentkezni
Javítva:
perl -pwe '
BEGIN{
%csere = (
"EZT:52798" => "ERRE",
"EZT:52799" => "EMERRE",
"EZT:52800" => "AMARRA",
);
$regexp_string = join "|", sort keys %csere;
$regexp = qr/($regexp_string)/;
}
# ez fut le minden sorra
s/$regexp/$csere{$1}/;
'
- A hozzászóláshoz be kell jelentkezni
Í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
- A hozzászóláshoz be kell jelentkezni
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.
- A hozzászóláshoz be kell jelentkezni
Talán az tért el a kettőnk mérésénél, hogy nálam 3100 sornyi cserélendő kifejezésről volt szó. Tehát nem ennyi helyettesítés történt, hanem 3100 sornyi mit-mire változat volt.
- A hozzászóláshoz be kell jelentkezni
Nem pontosan értem mit értesz 'sornyi' alatt.
Nálam a 10000 helyettesítés 10000 sorban történik a 864000-ből, tehát minden sorban legfeljebb egy.
- A hozzászóláshoz be kell jelentkezni
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).
- A hozzászóláshoz be kell jelentkezni
Világos, köszi.
- A hozzászóláshoz be kell jelentkezni
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!! :-)
- A hozzászóláshoz be kell jelentkezni