indietro

  • study SCALARE
  • study

    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";
        }