2010-05-27 32 views
33

Cách thông minh nhất để tìm kiếm thông qua một chuỗi các chuỗi cho một chuỗi phù hợp trong Perl là gì?Làm cách nào để tìm kiếm một mảng Perl cho một chuỗi phù hợp?

Một caveat, tôi muốn tìm kiếm được case-insensitive

nên "aAa" sẽ ở ("aaa","bbb")

+2

bạn sẽ tìm kiếm bao nhiêu lần trong danh sách? –

+0

nó sẽ chỉ được tìm kiếm một lần thực sự. thời gian chạy phức tạp không phải là những gì tôi thực sự lo lắng về – Mike

+1

không phải là nó quan trọng, hoặc là trong bất kỳ cách nào liên quan, nhưng nếu bạn giữ mảng của bạn trong một tập hợp các phím băm (tất cả với giá trị của 'bất cứ điều gì'), bạn có thể tìm thấy nếu nó tồn tại hoặc không nhanh hơn nhiều mặc dù trường hợp không nhạy cảm gây ra vấn đề ... oh yeah và rằng ~~ smartmatch chậm như có thể ... nếu không, hãy kết hợp với câu trả lời của Ether để chứng minh rằng câu trả lời đơn giản nhất là ' t luôn luôn là câu trả lời tốt nhất, ngay cả khi nó không phải là từ quan điểm của bạn, câu trả lời đúng. – osirisgothra

Trả lời

26

Tôi đoán

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

sẽ làm các trick.

+8

Có thể: @bar = grep (/^aaa $/i, @foo); Vì những gì bạn đã viết sẽ tìm kiếm tất cả các chuỗi bắt đầu bằng/aaa/i, nên nó cũng sẽ tìm/aaaa/và/aaaa + /. –

+0

Tôi nghĩ rằng nó sẽ hiệu quả hơn khi sử dụng 'grep {lc $ _ eq 'aaa'}, @ foo' do đó tránh sự cần thiết phải xử lý RegEx. – BlueMonkMN

+0

Tất cả đều đúng và rất hợp lệ tùy thuộc vào trường hợp sử dụng. Nhưng tôi đoán các ví dụ được đưa ra bởi OP chỉ hơi đại diện cho vấn đề của mình. –

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

Nó phụ thuộc vào những gì bạn muốn tìm kiếm để làm:

  • nếu bạn muốn tìm tất cả phù hợp, sử dụng được xây dựng trong grep:

    my @matches = grep { /pattern/ } @list_of_strings; 
    
  • nếu bạn muốn để tìm số khớp đầu tiên, sử dụng first trong List::Util:

    use List::Util 'first'; 
    my $match = first { /pattern/ } @list_of_strings; 
    
  • nếu bạn muốn tìm đếm của tất cả các trận đấu, sử dụng true trong List::MoreUtils:

    use List::MoreUtils 'true'; 
    my $count = true { /pattern/ } @list_of_strings; 
    
  • nếu bạn muốn biết chỉ số của trận đấu đầu tiên, sử dụng first_index trong List::MoreUtils :

    use List::MoreUtils 'first_index'; 
    my $index = first_index { /pattern/ } @list_of_strings; 
    
  • nếu bạn muốn chỉ đơn giản là k tại nếu có một trận đấu, nhưng bạn không quan tâm yếu tố nào đó là hay giá trị của nó, sử dụng any trong List::Util:

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

Tất cả những ví dụ làm những việc tương tự tại cốt lõi của họ, nhưng họ triển khai đã được tối ưu hóa rất nhiều để được nhanh chóng và sẽ nhanh hơn bất kỳ triển khai thuần túy nào mà bạn có thể tự viết với grep, map hoặc for loop.


Lưu ý rằng thuật toán để thực hiện vòng lặp là vấn đề riêng biệt so với thực hiện các kết quả phù hợp. Để khớp một chuỗi không phân biệt chữ hoa chữ thường, bạn có thể chỉ cần sử dụng cờ i trong mẫu: /pattern/i. Bạn chắc chắn nên đọc qua perldoc perlre nếu trước đây bạn chưa thực hiện điều đó.

+0

Bạn đang giả định "đối sánh" có nghĩa là đối sánh regex, nhưng ví dụ được đưa ra chỉ là bình đẳng (phân biệt chữ hoa chữ thường). – ysth

+0

Tôi đã đề nghị perlretut cho người mới bắt đầu thay vì perlre ... – Zaid

+0

'true' là một bit overkill IMO. Nó có nhanh hơn 'my $ count = grep {/ pattern /} @list_of_strings;'? – Zaid

5

Nếu bạn sẽ làm nhiều tìm kiếm của mảng, khớp luôn được định nghĩa là chuỗi tương đương, sau đó bạn có thể chuẩn hóa dữ liệu của bạn và sử dụng một băm.

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

Hãy để tôi nhấn mạnh rằng thực hiện tra cứu băm là tốt nếu bạn đang lên kế hoạch thực hiện nhiều lần tra cứu trên mảng. Ngoài ra, nó sẽ chỉ hoạt động nếu phù hợp có nghĩa là $foo eq $bar, hoặc các yêu cầu khác có thể được đáp ứng thông qua bình thường hóa (như trường hợp không nhạy cảm).

28

Perl 5.10+ chứa 'thông minh-match' hành ~~, mà trả về true nếu một yếu tố nào đó được chứa trong một mảng hoặc băm, và false nếu nó không (xem perlfaq4):

Các đẹp là nó cũng hỗ trợ các regex, nghĩa là yêu cầu không phân biệt dạng chữ của bạn có thể dễ dàng được chăm sóc:

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

Xin lưu ý rằng tính năng đối sánh thông minh là thử nghiệm ([source] (https://metacpan.org/pod/release/RJBS/perl-5.18.0/pod/perldelta.pod#The-smartmatch-family-of- tính năng-đang-thử nghiệm)) –

1

Kết hợp chuỗi Perl cũng có thể được sử dụng cho đơn giản có/không.

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

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

Điều này sẽ gây ra các kết quả dương tính giả trong một số trường hợp nhất định, xem xét ví dụ'my @foo = (" hello hello hello bar ");' – zb226

+0

Quan sát tốt về các mặt tích cực sai. Nhận thức được điều đó, tôi thấy điều này tốt đẹp và đơn giản cho thử nghiệm một từ. Nếu cần thiết, người ta luôn có thể thêm các ký tự phân cách bằng cách sử dụng tham gia - ví dụ bằng cách sử dụng \ x01 sẽ làm việc cho hầu hết các chuỗi văn bản. –

1

Đối với chỉ một kết quả trận đấu boolean hoặc cho một số lần xuất hiện, bạn có thể sử dụng:

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

Output:

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' 

Không yêu cầu để sử dụng một mô-đun.
Tất nhiên nó ít "có thể mở rộng" và linh hoạt như một số mã ở trên.
Tôi sử dụng tính năng này cho các câu trả lời của người dùng tương tác để khớp với một nhóm câu trả lời không xác định trước các trường hợp không được xác định trước.

Các vấn đề liên quan