Il modificatore ‘o’ per le espressioni regolari di Perl offre ancora qualche beneficio?

Era considerato utile includere il modificatore “o” alla fine delle espressioni regolari di Perl. L’attuale documentazione di Perl non sembra nemmeno elencarla, certamente non nella sezione dei modificatori di perlre .

Offre qualche vantaggio ora?

È ancora accettato, per ragioni di retrocompatibilità se non altro.


Come notato da JA Faucett e brian d foy, il modificatore ‘o’ è ancora documentato, se trovi i posti giusti da guardare (uno dei quali non è la documentazione perlre ). È menzionato nelle pagine perlop . Si trova anche nelle pagine perlreref .

Come notato da Alan M nella risposta accettata, la tecnica moderna migliore è di solito l’uso dell’operatore qr // (citato regex).

Sono sicuro che sia ancora supportato, ma è praticamente obsoleto. Se vuoi che la regex venga compilata una sola volta, è meglio usare un object regex, in questo modo:

 my $reg = qr/foo$bar/; 

L’interpolazione di $bar viene eseguita quando la variabile viene inizializzata, quindi verrà sempre utilizzata la regex memorizzata nella cache da quel momento all’interno dell’ambito che la include. Ma a volte vuoi che la regex venga ricompilata, perché vuoi che usi il nuovo valore della variabile. Ecco l’esempio di Friedl usato in The Book :

 sub CheckLogfileForToday() { my $today = (qw)[(localtime)[6]]; my $today_regex = qr/^$today:/i; # compiles once per function call while () { if ($_ =~ $today_regex) { ... } } } 

Nell’ambito della funzione, il valore di $ today_regex rimane lo stesso. Ma al prossimo richiamo della funzione, la regex verrà ricompilata con il nuovo valore di $today . Se avesse appena usato

 if ($_ =~ m/^$today:/io) 

… la regex non verrebbe mai aggiornata. Quindi, con la forma dell’object hai l’efficienza di / o senza sacrificare la flessibilità.

Il modificatore /o è nella documentazione perlop invece della documentazione perlre poiché è un modificatore di tipo preventivo piuttosto che un modificatore di espressioni regolari . Mi è sempre sembrato strano, ma è così. Dal Perl 5.20, è ora elencato in perlre semplicemente per notare che probabilmente non dovresti usarlo.

Prima di Perl 5.6, Perl ricompilava la regex anche se la variabile non era cambiata. Non hai più bisogno di farlo. È ansible utilizzare /o compilare la regex una volta nonostante ulteriori modifiche alla variabile, ma come le altre risposte indicate, qr// è migliore per questo.

Nella documentazione di Perl 5 versione 20.0 http://perldoc.perl.org/perlre.html si afferma

 Modifiers Other Modifiers … o - pretend to optimize your code, but actually introduce bugs 

che potrebbe essere un modo umoristico per dire che avrebbe dovuto eseguire un qualche tipo di ottimizzazione, ma l’implementazione è stata interrotta.

Quindi l’opzione potrebbe essere meglio evitata.

Questa è un’ottimizzazione nel caso in cui la regex include un riferimento variabile. Indica che la regex non cambia anche se ha una variabile al suo interno. Ciò consente ottimizzazioni che altrimenti non sarebbero possibili.

Ecco i tempi per i diversi modi di chiamare la corrispondenza.

 $ perl -v | grep version This is perl 5, version 20, subversion 1 (v5.20.1) built for x86_64-linux-gnu-thread-multi $ perl const-in-re-once.pl | sort 0.200 =~ CONST 0.200 =~ m/$VAR/o 0.204 =~ m/literal-wo-vars/ 0.252 =~ m,@{[ CONST ]},o 0.260 =~ $VAR 0.276 =~ m/$VAR/ 0.336 =~ m,@{[ CONST ]}, 

Il mio codice:

 #! /usr/bin/env perl use strict; use warnings; use Time::HiRes qw/ tv_interval clock_gettime gettimeofday /; use BSD::Resource qw/ getrusage RUSAGE_SELF /; use constant RE => qr{ https?:// (?:[^.]+-d-[^.]+\.)? (?:(?: (?:dev-)? nind[^.]* | mr02 )\.)? (?:(?:pda|m)\.)? (?:(?:news|haber)\.) (?:.+\.)? yandex\. .+ }x; use constant FINAL_RE => qr,^@{[ RE ]}(/|$),; my $RE = RE; use constant ITER_COUNT => 1e5; use constant URL => 'http://news.trofimenkov.nerpa.yandex.ru/yandsearch?cl4url=www.forbes.ru%2Fnews%2F276745-visa-otklyuchila-rossiiskie-banki-v-krymu&lr=213&lang=ru'; timeit( '=~ m/literal-wo-vars/', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m{ ^https?:// (?:[^.]+-d-[^.]+\.)? (?:(?: (?:dev-)? nind[^.]* | mr02 )\.)? (?:(?:pda|m)\.)? (?:(?:news|haber)\.) (?:.+\.)? yandex\. .+ (/|$) }x } } ); timeit( '=~ m/$VAR/', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m,^$RE(/|$), } } ); timeit( '=~ $VAR', ITER_COUNT, sub { my $r = qr,^$RE(/|$),o; for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ $r } } ); timeit( '=~ m/$VAR/o', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m,^$RE(/|$),o } } ); timeit( '=~ m,@{[ CONST ]},', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m,^@{[ RE ]}(/|$), } } ); timeit( '=~ m,@{[ CONST ]},o', ITER_COUNT, sub { for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ m,^@{[ RE ]}(/|$),o } } ); timeit( '=~ CONST', ITER_COUNT, sub { my $r = qr,^$RE(/|$),o; for (my $i = 0; $i < ITER_COUNT; ++$i) { URL =~ FINAL_RE } } ); sub timeit { my ($name, $iters, $code) = @_; #my $t0 = [gettimeofday]; my $t0 = (getrusage RUSAGE_SELF)[0]; $code->(); #my $el = tv_interval($t0); my $el = (getrusage RUSAGE_SELF)[0] - $t0; printf "%.3f\t%-17s\t%.9f\n", $el, $name, $el / $iters } 

Una cosa che, mistificamente, non è fare, consentire un blocco ONCE, almeno a 5.8.8.

perl -le 'for (1..3){ print; m/${\(print( "between 1 and 2 only"), 3)}/o and print "matched" }'