2012-02-06 22 views
7

tengo mi código como este:comparar cadenas múltiples en Perl

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

¿Existe de todos modos para optimizar este. Quiero algo como:

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

Si con "optimizar" quiere decir "hacerlo ir más rápido", la primera versión es óptima (si ordena las cuerdas para que la más probable esté al frente). – Mat

Respuesta

13

En función de los contenidos de las cadenas, una expresión regular es muy conveniente:

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

De no ser así, puede grep más de una lista:

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

muchas gracias ... La primera expresión funcionó pero con los corchetes eliminados: if ($ var = ~/^ str1 | str2 | str3 $ /) – sundar

+5

@ user988967, No, no es así. Sin los parens, coincidirá con 'str1A',' Astr2A' y 'Astr3'. – ikegami

+0

@ikegami, sí, estás en lo cierto. gracias .. Una consulta más. Estoy usando "use strict" en la parte superior de mi código. Entonces, ¿me aconsejaría usar "?:" – sundar

14

En Perl 5.10 o mejor:

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

El operador ~~ hace un smart match entre sus argumentos.

+1

+1; No tenía idea de que este operador existe. –

+1

@MarceloCantos: *** "El operador de Smartmatch es experimental y su comportamiento está sujeto a cambios". *** Recomiendo que lo evite – Borodin

+1

@Borodin: generalmente evito Perl, pero +1 para el cara a cara de todos modos. –

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

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

    Esto podría ser más rápido que usar grep PORQUE List::MoreUtils::any acabados temprana cuando se encuentra una coincidencia mientras que grep podría construir una lista completa de los partidos. Digo 'podría' porque Perl podría posiblemente optimizar if (grep .... Puede que no. Pero List::MoreUtils::any termina temprano, y es más descriptivo que el idioma if (grep ....

  2. Hacer un hash que tiene llaves de todas las cadenas que desea hacer coincidir

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

    Esto tiene el inconveniente de un tiempo de preparación y el costo de la memoria utilizada para el hash, pero la ventaja es que el tiempo de coincidencia es más como O (log N). Entonces, si tiene muchos valores diferentes de $var que desea probar, podría ser más rápido en general.

  3. Hacer una expresión regular que coincide con todas sus cadenas

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

    bien, así que esto está muy bien si sus cadenas son, literalmente, qw{str1 str2 str3}, pero lo que si es una lista de cadenas arbitrarias?

    Puede usar Regexp::Assemble para fusionar una lista de expresiones regulares en una sola expresión regular optimizada.

+0

[Regexp :: Assemble] (http://p3rl.org/Regexp::Assemble) no es necesario en los Perls más nuevos, ya que ahora las expresiones regulares tienen [Optimización de Trie] (http://perldoc.perl.org/perl5100delta.html # Trie-optimization-of-literal-string-alternations). –

0

estoy semi-broma, pero esto lo hará:

use Quantum::Superpositions; 

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

Ver también este Perl Monks thread

1

Para una lista de cadenas fijas, convertir su lista a un hash. Esto es especialmente útil si va a consultar su lista varias veces y si su lista aumenta.

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

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