2012-02-06 15 views
7

ho il mio codice come questo:Confrontando più stringhe in Perl

if ($var eq "str1" || $var eq "str2" || $var eq "str3") 
{ 
... 
} 

C'è comunque di ottimizzare questo. voglio qualcosa di simile:

if ($var eq ["str1" || "str2" || "str3"]) {...} 
+4

Se "ottimizza" intendi "fallo andare più veloce", la prima versione è ottimale (se ordini le stringhe in modo che il più probabile sia davanti). – Mat

risposta

13

A seconda del contenuto delle stringhe, una regex è molto conveniente:

if ($var =~ /^(str1|str2|str3)$/) { … } 

In mancanza di questo, è possibile grep su un elenco:

if (grep { $var eq $_ } qw{str1 str2 str3}) { … } 
+0

grazie mille .. La prima espressione ha funzionato ma con le parentesi rimosse: if ($ var = ~/^ str1 | str2 | str3 $ /) – sundar

+5

@ user988967, No, non lo è. Senza i paren, abbinerà 'str1A',' Astr2A' e 'Astr3'. – ikegami

+0

@ikegami, sì, hai ragione. grazie .. Un'altra query. Sto usando "use strict" nella parte superiore del mio codice. quindi mi consigli di usare "?:" – sundar

14

In Perl 5.10 o successivo:

if ($var ~~ [qw(str1 str2 str3)]) { ...} 

L'operatore ~~ fa uno smart match tra i suoi argomenti.

+1

+1; Non avevo idea che questo operatore esista. –

+1

@MarceloCantos: *** "L'operatore smartmatch è sperimentale e il suo comportamento è soggetto a modifiche." *** Vi consiglio di evitarlo – Borodin

+1

@Borodin: In genere evito Perl, ma +1 per l'heads-up comunque. –

2
  1. Usa List::MoreUtils qw{any}

    use List::MoreUtils qw{any}; 
    
    if (any { $var eq $_ } 'str1', 'str2', 'str3') { 
        ... 
    } 
    

    Questo potrebbe essere più veloce rispetto all'utilizzo di grep perchè List::MoreUtils::any termina presto quando trova una corrispondenza, mentre grep potrebbe costruire un elenco completo delle partite. Dico "potrebbe" perché Perl potrebbe idealmente ottimizzare if (grep .... Potrebbe non farlo. Ma List::MoreUtils::any termina presto ed è più descrittivo rispetto all'idioma if (grep ....

  2. Fare un hash che ha le chiavi di tutte le stringhe che si desidera abbinare

    my %matcher; 
    
    @matcher{qw{str1 str2 str3}} =(); 
    
    if (exists $matcher{$var}) { 
        ... 
    } 
    

    Questo ha lo svantaggio di un tempo di set-up e il costo della memoria utilizzata per l'hash, ma il vantaggio è che il tempo di corrispondenza è più simile a O (log N). Quindi, se hai un sacco di valori diversi di $var che vuoi testare, potrebbe essere più veloce nel complesso.

  3. Fai un espressione regolare che corrisponde a tutte le vostre corde

    if ($var =~ m/^str[123]$/so) { 
        ... 
    } 
    

    OK, quindi questo va bene se le corde sono letteralmente qw{str1 str2 str3}, ma cosa succede se si tratta di una lista di stringhe arbitrarie?

    È possibile utilizzare Regexp::Assemble per fondere insieme un elenco di espressioni regolari in una singola espressione regolare ottimizzata.

+0

[Regexp :: Assemble] (http://p3rl.org/Regexp::ssssemble) non è necessario sui più recenti Perls, poiché le espressioni regolari ora hanno [ottimizzazione Trie] (http://perldoc.perl.org/perl5100delta.html # Trie-ottimizzazione-of-letterale-string-alternanze). –

0

Sono semi-scherzando, ma questo lo farà:

use Quantum::Superpositions; 

if ($x == any($a, $b, $c)) { ... } 

Vedi anche questo Perl Monks thread

1

Per una lista di stringhe fisse, convertire la vostra lista per un hash. Questo è particolarmente utile se stai andando a controllare il tuo elenco più volte, e se la tua lista diventa più grande.

%on_my_list = map {; $_ => 1 } 'str1', 'str2', 'str3', ...; 

if ($on_my_list{$var}) { ... }