2010-09-28 9 views
12

Tôi có kịch bản Perl sau đếm số Fs và Ts trong một chuỗi:Làm cách nào để đếm các ký tự trong Perl?

my $str = "GGGFFEEIIEETTGGG"; 
my $ft_count = 0; 
$ft_count++ while($str =~ m/[FT]/g); 
print "$ft_count\n"; 

Có cách nào ngắn gọn hơn để có được số lượng (hay nói cách khác, để kết hợp dòng 2 và 3)?

Trả lời

24
my $ft_count = $str =~ tr/FT//; 

Xem perlop.

Nếu REPLACEMENTLIST trống, thì SEARCHLIST sẽ được nhân rộng. Sau này hữu ích khi đếm ký tự trong một lớp & hellip;

$cnt = $sky =~ tr/*/*/;  # count the stars in $sky 
    $cnt = tr/0-9//;   # count the digits in $_ 

Dưới đây là một chuẩn mực:

use strict; use warnings; 

use Benchmark qw(cmpthese); 

my ($x, $y) = ("GGGFFEEIIEETTGGG" x 1000) x 2; 

cmpthese -5, { 
    'tr' => sub { 
     my $cnt = $x =~ tr/FT//; 
    }, 
    'm' => sub { 
     my $cnt =()= $y =~ m/[FT]/g; 
    }, 
}; 
  Rate  tr  m 
    Rate  m tr 
m 108/s -- -99% 
tr 8118/s 7440% --

Với ActiveState Perl 5.10.1.1006 trên 32 Windows XP.

Sự khác biệt có vẻ là trần trụi với

C:\Temp> c:\opt\strawberry-5.12.1\perl\bin\perl.exe t.pl 
     Rate  m  tr 
m 88.8/s  -- -100% 
tr 25507/s 28631%  --
+0

điều này sẽ là 'my $ ft_count = $ str = ~ tr/FT/FT /;', nếu không nó sẽ xóa các ký tự khỏi '$ str' – Hasturkun

+0

ok, bỏ qua điều đó. bạn vẫn có thể loại bỏ các dấu ngoặc, mặc dù. – Hasturkun

+0

Nó tính các dấu ngoặc vuông. Phải là 'tr/FT // ' – Toto

8

Có, bạn có thể sử dụng CountOf secret operator:

my $ft_count =()= $str =~ m/[FT]/g; 
+2

Còn được gọi là toán tử goatse;) '=() =' – Daenyth

+0

ôi trời ơi ... tyvm Daenyth ......: O tất cả điều này để nói rằng những người thông tin thực sự điên rồ – Sosi

0

Bạn có thể kết hợp dòng 2, 3 và 4 vào một mặt hàng như vậy:

my $str = "GGGFFEEIIEETTGGG"; 
print $str =~ s/[FT]//g; #Output 4; 
+2

Là một nhận xét về câu trả lời khác, này sẽ là tốt hơn như một bình luận hơn là một câu trả lời :) – ysth

+0

@ ysh, cảm ơn cho bình luận. Tôi đã không nhận ra câu trả lời của tôi thực sự là một bình luận về câu trả lời khác, phải không? OP hỏi [Có cách nào ngắn gọn hơn để lấy số lượng (nói cách khác, để kết hợp dòng 2 và 3) và đây là câu trả lời của tôi cho câu hỏi. Đã có ai đó đã đề cập đến những gì tôi đề nghị? – Mike

+0

@ysth, bài đăng gốc có thể là bản sao của [http://stackoverflow.com/questions/1849329/is-there-a-perl-shortcut-to-count-the-number-of-matches-in- này a-string/1850686 # 1850686] và tôi đăng một giải pháp tương tự cho câu hỏi đó. Tôi nghĩ rằng bài đăng này có thể được kết hợp với bài đăng đó. – Mike

8

Khi toán tử "m" có cờ/g VÀ được thực thi trong ngữ cảnh danh sách, nó trả về một danh sách o f phù hợp với chất nền. Vì vậy, một cách khác để thực hiện việc này là:

my @ft_matches = $str =~ m/[FT]/g; 
my $ft_count = @ft_matches; # count elements of array 

Nhưng đó vẫn là hai dòng. Một mẹo lừa đảo khác có thể làm cho nó ngắn hơn:

my $ft_count =() = $str =~ m/[FT]/g; 

"() =" buộc "m" nằm trong ngữ cảnh danh sách. Việc gán một danh sách với các phần tử N vào một danh sách các biến số không thực sự làm bất cứ điều gì. Nhưng sau đó khi biểu thức gán này được sử dụng trong ngữ cảnh vô hướng ($ ft_count = ...), toán tử "=" trả về số phần tử từ bên phải - chính xác những gì bạn muốn. Điều này là cực kỳ kỳ lạ khi lần đầu tiên gặp phải, nhưng "=() =" thành ngữ là một thủ thuật Perl hữu ích để biết, cho "đánh giá trong bối cảnh danh sách, sau đó nhận được kích thước của danh sách".

Lưu ý: Tôi không có dữ liệu nào trong số này hiệu quả hơn khi xử lý các chuỗi lớn. Trong thực tế, tôi nghi ngờ mã ban đầu của bạn có thể là tốt nhất trong trường hợp đó.