2010-05-27 13 views
33

Qual è il modo più intelligente di cercare attraverso una serie di stringhe per una stringa corrispondente in Perl?Come si cerca un array Perl per una stringa corrispondente?

Un avvertimento, vorrei la ricerca ad essere case-insensitive

così "aAa" sarebbe in ("aaa","bbb")

+2

quante volte cercherete nella lista? –

+0

verrà cercato solo una volta in realtà. la complessità del runtime non è quello che sono veramente preoccupato per – Mike

+1

, non che sia importante, o che sia in qualche modo correlato, ma se hai tenuto il tuo array in una serie di chiavi hash (tutte con il valore di "qualunque") puoi trovare se esiste o meno molto velocemente, anche se l'insensibilità al caso pone un problema ... oh sì e che ~~ smartmatch è lento come può essere ... altrimenti, attenersi alla risposta ben documentata di Ether che dimostra che la risposta più semplice non è t sempre la risposta migliore, anche se non è dal tuo punto di vista, la risposta corretta. – osirisgothra

risposta

26

Credo

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

farebbe il trucco.

+8

Forse: @bar = grep (/^aaa $/i, @foo); Poiché ciò che hai scritto cercherà tutte le stringhe che iniziano con/aaa/i, quindi troverà anche/aaaa/e/aaaa + /. –

+0

Penso che sarebbe più efficiente usare 'grep {lc $ _ eq 'aaa'}, @ foo' evitando così la necessità dell'elaborazione di RegEx. – BlueMonkMN

+0

Tutto vero, e molto valido in base al caso d'uso. Ma immagino che gli esempi forniti dall'OP siano solo leggermente rappresentativi del suo 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

Dipende da ciò che si desidera che la ricerca da fare:

  • se si vuole trovare tutte le partite, utilizzare il built-in grep:

    my @matches = grep { /pattern/ } @list_of_strings; 
    
  • se si desidera per trovare la prima corrispondenza , utilizzare first in List::Util:

    use List::Util 'first'; 
    my $match = first { /pattern/ } @list_of_strings; 
    
  • se si vuole trovare il conteggio di tutte le partite, utilizzare true in List::MoreUtils:

    use List::MoreUtils 'true'; 
    my $count = true { /pattern/ } @list_of_strings; 
    
  • se si desidera conoscere l'indice della prima partita, utilizzare first_index in List::MoreUtils :

    use List::MoreUtils 'first_index'; 
    my $index = first_index { /pattern/ } @list_of_strings; 
    
  • se si desidera semplicemente k ora se ci fosse una corrispondenza, ma non importa quale elemento è stato o il suo valore, utilizzare any in List::Util:

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

Tutti questi esempi fanno cose simili nella loro essenza, ma la loro le implementazioni sono state fortemente ottimizzate per essere veloci e saranno più veloci di qualsiasi implementazione pura perl che potresti scrivere con grep, map o for loop.


Si noti che l'algoritmo per eseguire il ciclo è un problema separato rispetto all'esecuzione delle singole corrispondenze. Per abbinare una stringa senza distinzione tra maiuscole e minuscole, è sufficiente utilizzare il flag i nel motivo: /pattern/i. Dovresti assolutamente leggere lo perldoc perlre se non lo hai fatto in precedenza.

+0

Si presume che "corrispondenza" indichi una corrispondenza regolare, ma l'esempio fornito è l'uguaglianza giusta (maiuscole e minuscole). – ysth

+0

Avrei suggerito perlretut per principianti invece di perlre ... – Zaid

+0

'true' è un po 'eccessivo IMO. È più veloce di 'my $ count = grep {/ pattern /} @list_of_strings;'? – Zaid

5

Se si farà molti ricerche della matrice, E corrispondenza sempre è definito come equivalenza tra stringhe, allora si può normalizzare i dati e utilizzare 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"; 

Vorrei sottolineare che facendo una ricerca hash è buono se si sta progettando di fare molte ricerche sulla matrice. Inoltre, funzionerà solo se la corrispondenza indica che $foo eq $bar o altri requisiti che possono essere soddisfatti tramite la normalizzazione (come insensibilità alle maiuscole/minuscole).

28

Perl 5.10+ contiene la 'smart-match' operatore ~~, che restituisce vero se un certo elemento è contenuto in un array o hash, e falso se non esiste (vedi perlfaq4):

La bella cosa è che supporta anche le espressioni regolari, il che significa che il vostro requisito maiuscole e minuscole può essere facilmente curato:

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

Si prega di notare che la funzione Smart Match è sperimentale ([fonte] (https://metacpan.org/pod/release/RJBS/perl-5.18.0/pod/perldelta.pod#The-smartmatch-family-of- features-are-now-experimental)) –

1

Perl partita stringa può essere utilizzato anche per un semplice sì/no.

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

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

Ciò causerà falsi positivi in ​​determinate situazioni, ad esempio'my @foo = (" ciao ciao ciao mondo ");' – zb226

+0

Buona osservazione sui falsi positivi. Essendo consapevole di ciò, trovo questo semplice e simpatico per i test di una sola parola. Se necessario, si potrebbero sempre aggiungere caratteri delimitatori usando join - ad esempio usando \ x01 funzionerebbe per la maggior parte delle stringhe di testo. –

1

Per un risultato della partita booleano o per un conteggio di occorrenze, è possibile utilizzare:

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

uscita:

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' 

Non richiede a uso un modulo.
Ovviamente è meno "espandibile" e versatile come alcuni codici sopra.
Lo uso per le risposte interattive dell'utente in modo che corrispondano a un insieme predefinito di risposte maiuscole/minuscole.

Problemi correlati