2010-05-27 18 views
33

¿Cuál es la forma más inteligente de buscar a través de una matriz de cadenas una cadena coincidente en Perl?¿Cómo busco una matriz Perl para una cadena coincidente?

Una advertencia, me gustaría que la búsqueda de ser sensible a las mayúsculas

por lo "aAa" estaría en ("aaa","bbb")

+2

¿cuántas veces buscará en la lista? –

+0

solo se buscará una vez en realidad. la complejidad del tiempo de ejecución no es lo que realmente me preocupa – Mike

+1

no es importante, o está relacionado de alguna manera, pero si mantienes tu matriz en un conjunto de claves hash (todas con el valor de 'lo que sea') puedes encontrar si existe o no mucho más rápido, aunque la insensibilidad a las mayúsculas sí plantea un problema ... oh sí, y eso ~~ smartmatch es lento, como puede ser ... de lo contrario, sigue con la bien documentada respuesta de Ether que demuestra que la respuesta más simple no es Siempre es la mejor respuesta, incluso si no es desde su punto de vista, la respuesta correcta. – osirisgothra

Respuesta

26

supongo

@foo = ("aAa", "bbb"); 
@bar = grep(/^aaa/i, @foo); 
print join ",",@bar; 

haría el truco.

+8

Tal vez: @bar = grep (/^aaa $/i, @foo); Como lo que escribió buscará todas las cadenas que comiencen con/aaa/i, por lo que también encontrará/aaaa/y/aaaa + /. –

+0

Creo que sería más eficiente usar 'grep {lc $ _ eq 'aaa'}, @ foo' evitando así la necesidad de procesar RegEx. – BlueMonkMN

+0

Todo verdadero y muy válido según el caso de uso. Pero supongo que los ejemplos dados por OP son solo un poco representativos de su problema. –

5
#!/usr/bin/env perl 

use strict; 
use warnings; 
use Data::Dumper; 

my @bar = qw(aaa bbb); 
my @foo = grep {/aAa/i} @bar; 

print Dumper \@foo; 
131

Depende de lo que desea que la búsqueda debe hacer:

  • si usted quiere encontrar todos los partidos, utilice la incorporada en grep:

    my @matches = grep { /pattern/ } @list_of_strings; 
    
  • si quieres para encontrar el primer partido , use first en List::Util:

    use List::Util 'first'; 
    my $match = first { /pattern/ } @list_of_strings; 
    
  • si quiere encontrar el recuento de todos los partidos, utilice true en List::MoreUtils:

    use List::MoreUtils 'true'; 
    my $count = true { /pattern/ } @list_of_strings; 
    
  • si desea conocer el índice del primer partido, utilice first_index en List::MoreUtils :

    use List::MoreUtils 'first_index'; 
    my $index = first_index { /pattern/ } @list_of_strings; 
    
  • si quieres simplemente k Ahora si había un partido, pero no me importa qué elemento era o su valor, utilice any en List::Util:

    use List::Util 1.33 'any'; 
    my $match_found = any { /pattern/ } @list_of_strings; 
    

Todos estos ejemplos hacen cosas similares en su núcleo, pero su las implementaciones se han optimizado en gran medida para ser rápidas, y serán más rápidas que cualquier implementación pura-perl que pueda escribir usted mismo con grep, map o for loop.


Tenga en cuenta que el algoritmo para hacer el bucle es un tema aparte de la realización de los partidos individuales. Para hacer coincidir insensiblemente una cadena, puede simplemente usar la bandera i en el patrón: /pattern/i. Definitivamente debe leer perldoc perlre si no lo ha hecho anteriormente.

+0

Está asumiendo que "coincidencia" significa coincidencia de expresiones regulares, pero el ejemplo dado es justo (no distingue entre mayúsculas y minúsculas) la igualdad. – ysth

+0

Hubiera sugerido perlretut para principiantes en lugar de perlre ... – Zaid

+0

'true' es un poco exagerado IMO. ¿Es más rápido que 'my $ count = grep {/ pattern /} @list_of_strings;'? – Zaid

5

Si va a hacer muchos búsquedas de la matriz, Y juego siempre se define como la equivalencia cadena, entonces se puede normalizar sus datos y utilizar un hash.

my @strings = qw(aAa Bbb cCC DDD eee); 

my %string_lut; 

# Init via slice: 
@string_lut{ map uc, @strings } =(); 

# or use a for loop: 
# for my $string (@strings) { 
#  $string_lut{ uc($string) } = undef; 
# } 


#Look for a string: 

my $search = 'AAa'; 

print "'$string' ", 
    (exists $string_lut{ uc $string ? "IS" : "is NOT"), 
    " in the array\n"; 

Déjenme enfatizar que hacer una búsqueda hash es bueno si está planeando hacer muchas búsquedas en la matriz. Además, solo funcionará si la coincidencia significa que $foo eq $bar u otros requisitos que se pueden cumplir mediante la normalización (como la insensibilidad de mayúsculas y minúsculas).

28

Perl 5.10+ contiene el 'smart-partido' operador ~~, que devuelve verdadero si un determinado elemento está contenido en una matriz o hachís, y falso si no lo hace (ver perlfaq4):

El agradable cosa es que también soporta expresiones regulares, lo que significa que su requerimiento de mayúsculas y minúsculas puede ser fácilmente atendidos:

use strict; 
use warnings; 
use 5.010; 

my @array = qw/aaa bbb/; 
my $wanted = 'aAa'; 

say "'$wanted' matches!" if /$wanted/i ~~ @array; # Prints "'aAa' matches!" 
+1

Tenga en cuenta que la función de coincidencia inteligente es experimental ([fuente] (https://metacpan.org/pod/release/RJBS/perl-5.18.0/pod/perldelta.pod#The-smartmatch-family-of- features-are-now-experimental)) –

1

cadena partido Perl también se puede utilizar para un simple sí/no.

my @foo=("hello", "world", "foo", "bar"); 

if ("@foo" =~ /\bhello\b/){ 
    print "found"; 
} 
else{ 
    print "not found"; 
} 
+1

Esto causará falsos positivos en ciertas situaciones, considere por ej.'my @foo = (" hello world hello bar ");' – zb226

+0

Buena observación sobre los falsos positivos. Al ser consciente de esto, me parece agradable y simple para las pruebas de una sola palabra. Si es necesario, siempre se pueden agregar caracteres de delimitador usando join, por ejemplo, usar \ x01 funcionaría para la mayoría de las cadenas de texto. –

1

Por sólo un resultado del partido booleano o para un recuento de los sucesos, se puede utilizar:

use 5.014; use strict; use warnings; 
my @foo=('hello', 'world', 'foo', 'bar', 'hello world', 'HeLlo'); 
my $patterns=join(',',@foo); 
for my $str (qw(quux world hello hEllO)) { 
    my $count=map {m/^$str$/i} @foo; 
    if ($count) { 
     print "I found '$str' $count time(s) in '$patterns'\n"; 
    } else { 
     print "I could not find '$str' in the pattern list\n" 
    }; 
} 

Salida:

I could not find 'quux' in the pattern list 
I found 'world' 1 time(s) in 'hello,world,foo,bar,hello world,HeLlo' 
I found 'hello' 2 time(s) in 'hello,world,foo,bar,hello world,HeLlo' 
I found 'hEllO' 2 time(s) in 'hello,world,foo,bar,hello world,HeLlo' 

No requiere a uso un módulo.
Por supuesto, es menos "ampliable" y versátil que algunos códigos anteriores.
Utilizo esto para que las respuestas de los usuarios interactivos coincidan con un conjunto predefinido de respuestas no sensibles.

Cuestiones relacionadas