Czy istnieje skrót Perla do zliczania liczby dopasowań w łańcuchu?
Załóżmy, że mam:
my $string = "one.two.three.four";
Jak powinienem grać z kontekstem, aby uzyskać liczbę razy wzór znalazł dopasowanie (3)? Czy można to zrobić za pomocą jednego linera?
Próbowałem tego:
my ($number) = scalar($string=~/\./gi);
Myślałem, że umieszczając nawiasy wokół $number
, wymuszę kontekst tablicy, a używając scalar
, uzyskam liczbę. Jednak wszystko co dostaję to 1
.
8 answers
To umieszcza regex w kontekście skalarnym, co nie jest tym, czego chcesz. Zamiast tego, umieść Wyrażenie regularne w kontekście listy (aby uzyskać liczbę dopasowań) i umieść to w kontekście skalarnym.
my $number = () = $string =~ /\./gi;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-21 19:20:03
Myślę, że najlepszym sposobem na opisanie tego byłoby uniknięcie natychmiastowego oddania do skalara. Najpierw Przypisz do tablicy, a następnie użyj tej tablicy w kontekście skalarnym. W zasadzie to samo zrobi idiom = () =
, ale bez (rzadko używanego) idiomu:
my $string = "one.two.three.four";
my @count = $string =~ /\./g;
print scalar @count;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-04 22:58:27
Zobacz też Perlfaq4:
Istnieje wiele sposobów, z różną skutecznością. Jeśli chcesz policzyć pewien pojedynczy znak (X) w łańcuchu, możesz użyć funkcji tr/// w następujący sposób:
Jest to w porządku, jeśli szukasz tylko jednego znaku. Jeśli jednak próbujesz zliczyć wiele podciągów znaków w większym łańcuchu, tr / / / nie będzie działać. Możesz zawinąć pętlę while () wokół globalnego dopasowania wzorca. Na przykład, Policzmy liczby całkowite ujemne:$string = "ThisXlineXhasXsomeXx'sXinXit"; $count = ($string =~ tr/X//); print "There are $count X characters in the string";
$string = "-9 55 48 -2 23 -76 4 14 -44"; while ($string =~ /-\d+/g) { $count++ } print "There are $count negative numbers in the string";
Inna wersja używa globalnego dopasowania w kontekście listy, a następnie przypisuje wynik skalarowi, tworząc liczbę dopasowań.
$count = () = $string =~ /-\d+/g;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-04 20:20:42
Spróbuj tego:
my $string = "one.two.three.four";
my ($number) = scalar( @{[ $string=~/\./gi ]} );
Zwraca 3
dla mnie. Poprzez utworzenie referencji do tablicy Wyrażenie regularne jest obliczane w kontekście listy, a @{..}
odsyła do tablicy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-04 20:08:52
Czy poniższy kod jest jednowierszowy?
print $string =~ s/\./\./g;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-05 01:07:52
Another way,
my $string = "one.two.three.four";
@s = split /\./,$string;
print scalar @s - 1;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-04 23:56:44
my $count = 0;
my $pos = -1;
while (($pos = index($string, $match, $pos+1)) > -1) {
$count++;
}
Sprawdzone przez Benchmark, to dość szybko
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-09 00:10:44
Metoda Friedo to: $a = () = $b =~ $c
.
Ale można to jeszcze bardziej uprościć do tylko ($a) = $b =~ $c
, w ten sposób :
my ($matchcount) = $text =~ s/$findregex/ /gi;
Możesz po prostu owinąć to w funkcję, getMatchCount()
, i nie martwić się o to, że zniszczy przekazany ciąg.
Z drugiej strony, możesz dodać swap, który może być nieco bardziej obliczeniowy, ale nie powoduje zmiany ciągu znaków.
my ($matchcount) = $text =~ s/($findregex)/$1/gi;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-19 16:19:26