2015-12-23 37 views
5

Czułem, że musi istnieć lepszy sposób zliczania występowania zamiast pisania sub w perlu, powłoki w systemie Linux.Czy istnieje lepszy sposób zliczania występowania char w ciągu znaków?

#/usr/bin/perl -w 
use strict; 
return 1 unless $0 eq __FILE__; 
main() if $0 eq __FILE__; 
sub main{ 
    my $str = "ru8xysyyyyyyysss6s5s"; 
    my $char = "y"; 
    my $count = count_occurrence($str, $char); 
    print "count<$count> of <$char> in <$str>\n"; 
} 
sub count_occurrence{ 
    my ($str, $char) = @_; 
    my $len = length($str); 
    $str =~ s/$char//g; 
    my $len_new = length($str); 
    my $count = $len - $len_new; 
    return $count; 
} 
+1

Robert, dzięki, dodam gramatyki przyszłości. – Gang

Odpowiedz

9

Liczenie wystąpień znaku w łańcuchu można wykonać za pomocą jednego wiersza w Perlu (w porównaniu do 4 wierszy). Nie ma potrzeby stosowania sub (chociaż nie ma nic złego w enkapsulacji funkcji w sub). Od perlfaq4 "How can I count the number of occurrences of a substring within a string?"

use warnings; 
use strict; 

my $str = "ru8xysyyyyyyysss6s5s"; 
my $char = "y"; 
my $count =() = $str =~ /\Q$char/g; 
print "count<$count> of <$char> in <$str>\n"; 
2

w A piękny * Bash/Coreutils/Grep jedno-liner:

$ str=ru8xysyyyyyyysss6s5s 
$ char=y 
$ fold -w 1 <<< "$str" | grep -c "$char" 
8 

Albo

$ grep -o "$char" <<< "$str" | wc -l 
8 

Pierwszy z nich działa tylko wtedy podciąg jest po prostu jedna postać długa; drugi działa tylko wtedy, gdy podciągi nie zachodzą na siebie.

* Niezupełnie.

+0

oba działają dobrze, dodałem je do skrzynki z narzędziami, po raz pierwszy usłyszałem zgięcie cmd, doceniam! – Gang

+1

@gliang: To trochę jak "split //" Basha, również niedawno to odkryłem. Cieszę się, że są one przydatne! –

2

toolic Podał poprawną odpowiedź, ale możesz rozważyć nie zakodowanie swoich wartości, aby program mógł być ponownie użyty.

use strict; 
use warnings; 

die "Usage: $0 <text> <characters>" if @ARGV < 1; 
my $search = shift;     # the string you are looking for 
my $str;        # the input string 
if (@ARGV && -e $ARGV[0] || [email protected]) { # if str is file, or there is no str 
    local $/;       # slurp input 
    $str = <>;       # use diamond operator 
} else {        # else just use the string 
    $str = shift; 
} 
my $count =() = $str =~ /\Q$search\E/gms; 
print "Found $count of '$search' in '$str'\n"; 

To pozwoli Ci korzystać z programu liczyć na występowanie znaku lub ciągu znaków, wewnątrz ciągu znaków, pliku lub standardowego wejścia. Na przykład:

count.pl needles haystack.txt 
some_process | count.pl foo 
count.pl x xyzzy 
+0

czym jest GMS? g - dla wszystkich przypadków m dla meczu, dla? – Gang

+1

@gliang: "Traktuj ciąg jako pojedynczą linię", tzn. '.' dopasowuje znaki nowej linii, których normalnie nie ma, zobacz http://perldoc.perl.org/perlre.html#Modifiers –

+0

Benjamin, dzięki, to jest nie to, co myślałem, że to jest. Przeczytam dokument ponownie. – Gang

4

Jeśli znak jest stała, po to najlepiej:

my $count = $str =~ tr/y//; 

Jeśli znak jest zmienna, użyję następujące:

my $count = length($str =~ s/[^\Q$char\E]//rg); 

I” d używaj tylko poniższych, jeśli chcę kompatybilność z wersjami Perla starszymi niż 5.14 (ponieważ jest wolniejsza i zużywa więcej pamięci):

my $count =() = $str =~ /\Q$char/g; 

następujących zastosowań nie pamięta, ale może być nieco powolny:

my $count = 0; 
++$count while $str =~ /\Q$char/g; 
+0

Jesteście świetni, perl zawsze mnie zaskoczy !, dzięki. – Gang