2012-03-02 47 views
32

Cách nhanh nhất để đếm số lần một chuỗi nhất định xuất hiện trong một chuỗi lớn hơn là gì? Dự đoán tốt nhất của tôi là thay thế tất cả các trường hợp của chuỗi đó bằng không, tính toán độ dài của độ dài và chia cho độ dài của chuỗi con, nhưng điều đó có vẻ khá chậm và tôi cần phân tích một lượng lớn dữ liệu.Đếm số lần xuất hiện của một chuỗi trong một chuỗi khác (Perl)

+0

Có thể muốn kiểm tra này ra ... mặc dù đó là từ năm 1999, và có nhiều khả năng những cách khác để làm điều này loại hiệu quả: http://www.perlmonks.org/?node=How%20can%20I%20count%20the%20number%20of%20occurrences%20of%20a%20substring%20within%20a%20string%3F – summea

+7

'perldoc -q count ' – toolic

+2

Những nội dung này có thể trùng lặp không? – tchrist

Trả lời

57

Bạn có thể nắm bắt các chuỗi, sau đó đếm chúng. Nó có thể được thực hiện bằng cách áp dụng một bối cảnh danh sách để chụp với ():

my $x = "foo"; 
my $y = "foo foo foo bar"; 
my $c =() = $y =~ /$x/g; # $c is now 3 

Bạn cũng có thể chụp đến một mảng và đếm mảng. Cùng nguyên tắc, kỹ thuật khác nhau:

my @c = $y =~ /$x/g; 
my $count = @c; 
+0

Cảm ơn! Nó rất giống với giải pháp thứ hai. – ronash

+2

@ronash Đó là giải pháp tương tự. Một sử dụng biến tạm thời, cái kia thì không. Bạn cũng có thể làm 'my $ count = @c = $ y = ~/$ x/g', nhưng thay vào đó bạn có thể đơn giản bỏ qua' @ c' và sử dụng '()'. Cái nào là tốt nhất, nếu bạn không quan tâm đến các trận đấu thực tế. – TLP

+2

Điều này không có tác dụng nếu '$ x' chứa các ký tự regex nhất định, vì' $ x' được hiểu là regex. Thêm '\ Q' để sửa lỗi này, vd. '/ \ Q $ x/g'. Xem 'quotemeta' để biết thêm thông tin. – tuomassalo

8

Bạn có thể sử dụng regex chung. Một cái gì đó như:

my @matches = $bigstring =~ /($littlestring)/g; 
my $count = @matches; 
+0

Điều đó có vẻ giống như giải pháp đơn giản nhất, vì vậy tôi nghĩ tôi sẽ sử dụng nó, trừ khi có một giải pháp nhanh hơn? Cảm ơn! – ronash

+0

Tôi không chắc chắn về tốc độ của regex, nhưng tôi chắc chắn rằng chỉ cần sử dụng các hoạt động phù hợp nhanh hơn thay thế. Và tôi không thể nghĩ ra một giải pháp không liên quan gì đến regex (sẽ rất thú vị nếu bạn nhìn thấy khác!) – MattLBeck

14
my $string = "aaaabbabbba"; 
my @count = ($string =~ /a/g); 
print @count . "\n"; 

hoặc

my $count = ($string =~ s/a/a/g); 
+0

Cảm ơn! Điều đó có hiệu quả nếu có nhiều hơn một lá thư được tìm kiếm không? – ronash

+1

Erm, vâng ... đó là cụm từ thông dụng, bạn có thể đối sánh với bất kỳ thứ gì. –

+0

Trên giải pháp thứ hai của bạn, sẽ không tr/a/a/g là một giải pháp tốt hơn, bởi vì bạn thay thế các nhân vật của chính nó và tr là nhanh hơn trên đó hơn s? – nerdbeere

4

Chỉ cần cho đầy đủ bạn liên tục có thể gọi hàm chỉ mục trong một vòng lặp và đếm tất cả các lần nó trở lại chỉ số của chuỗi con trong chuỗi và thay đổi vị trí bắt đầu. Điều đó sẽ tránh sử dụng regexes, và trong thử nghiệm của tôi là nhanh hơn một chút so với các giải pháp regex.

Tôi đã thích nghi một tiểu để làm điều đó từ đây: http://www.misc-perl-info.com/perl-index.html

sub occurrences { 

    my($x, $y) = @_; 

    my $pos = 0; 
    my $matches = 0; 

    while (1) { 
     $pos = index($y, $x, $pos); 
     last if($pos < 0); 
     $matches++; 
     $pos++; 
    } 

    return $matches; 
} 
Các vấn đề liên quan