Impiega del tempo addizionale per studiare lo SCALARE ($_ se non viene
specificato) in previsione di un gran numero di corrispondenze del pattern
sulla stringa, prima che sia modificata. Può far risparmiare
tempo o meno, a seconda della natura e del numero di pattern che state
cercando, e della distribuzione delle frequenze di caratteri nella
stringa da cercare, probabilmente vale la pena di confrontare i tempi
di esecuzione con o senza study per vedere quale è più veloce.
I cicli che controllano la presenza di brevi e numerose stringhe costanti
(inclusa la parte costante di pattern più complessi) ne beneficeranno
in maggior misura. Potete avere una sola study attiva per volta, se
"studiate" uno scalare diverso il primo è "non studiato". (La maniera
in cui funziona study è la seguente: viene generata una lista
concatenata di ogni carattere nella stringa, in modo tale da conoscere,
per esempio, dove stanno tutti i caratteri 'k'. Da ogni stringa di
ricerca, viene selezionato il carattere più raro, secondo delle tabelle
statiche di frequenza, costruite con alcuni programmi C e del testo in
inglese. Vengono esaminate solo le posizioni che contengono questi caratteri
"più rari").
Per esempio, ecco un ciclo che inserisce un indice producendo delle annotazioni prima di ogni linea che contiene un certo pattern:
while (<>) {
study;
print ".IX pippo\n" if /\bpippo\b/;
print ".IX pluto\n" if /\bpluto\b/;
print ".IX paperino\n" if /\bpaperino\b/;
# ...
print;
}
Cercando /\bpippo\b, verranno controllati solo le posizioni in $_ che
contengono p, poiché essa è più rara di o.
In generale, e fatta eccezione per i casi patologici, si ottiene un grande
vantaggio. L'unico problema è se viene risparmiato più tempo
di quanto se ne perde inizialmente per costruire la lista linkata.
Va notato che se dovete cercare stringhe che non conoscerete se non quando
il programma sarà eseguito, potete costruire l'intero loop come una
stringa, e valutar quest'ultima per evitare la ricompilazione dei
pattern tutte le volte. Messo assieme alla pratica di rendere indefinito
$/ per leggere interi file come fossero un solo record, il tutto può
risultare molto veloce, spesso più veloce di fgrep(1). Il codice che
segue controlla una lista di file (@files) cercando una lista di
parole (@parole), e stampa i nomi dei file che contengono una
corrispondenza:
$cerca = 'while (<>) { study;';
foreach $parola (@parole) {
$cerca .= "++\$viste{\$ARGV} if /\\b$parola\\b/;\n";
}
$cerca .= "}";
@ARGV = @files;
undef $/;
eval $cerca; # questa salta all'occhio
$/ = "\n"; # rimette il normale delimitatore di input
foreach $file (sort keys(%viste)) {
print $file, "\n";
}