Есть ярлык на Perl для подсчета количества совпадений в строке?


Предположим, у меня есть:

my $string = "one.two.three.four";

как я должен играть с контекстом, чтобы получить число раз картина матча (3)? Можно ли это сделать с помощью одного вкладыша?

Я попытался это:

my ($number) = scalar($string=~/./gi);

Я думал, что поставив скобки $number, Я бы принудительно контекст массива, и с помощью scalar, Я бы получил счет. Однако, все, что я получаю это 1.

8 70

8 ответов:

это помещает само регулярное выражение в скалярный контекст, что не то, что вы хотите. Вместо этого поместите регулярное выражение в контекст списка (чтобы получить количество совпадений) и поместите это в скалярном контексте.

 my $number = () = $string =~ /\./gi;

Я думаю, что самым ясным способом описать это было бы избежать мгновенного приведения к скаляру. Сначала назначьте массив, а затем используйте этот массив в скалярном контексте. Основно = () = идиома подойдет, но без (редко используемой) идиомы:

my $string = "one.two.three.four";
my @count = $string =~ /\./g;
print scalar @count;

кроме того, см. Perlfaq4:

есть несколько способов, с разной эффективностью. Если вы хотите, чтобы количество определенного одного символа (X) в строке, вы можете использовать функцию tr/// следующим образом:

$string = "ThisXlineXhasXsomeXx'sXinXit";
$count = ($string =~ tr/X//);
print "There are $count X characters in the string";

Это нормально, если вы просто ищете один персонаж. Однако, если вы пытаетесь подсчитать несколько символьных подстрок в более крупной строке, tr/ / / не будет работать. Что вы можете сделать, это обернуть цикл while () вокруг глобального совпадение рисунка. Например, посчитаем отрицательные целые числа:

$string = "-9 55 48 -2 23 -76 4 14 -44";
while ($string =~ /-\d+/g) { $count++ }
print "There are $count negative numbers in the string";

другая версия использует глобальное совпадение в контексте списка, затем присваивает результат скаляру, производя подсчет количества совпадений.

$count = () = $string =~ /-\d+/g;

попробуйте это:


my $string = "one.two.three.four";
my ($number) = scalar( @{[ $string=~/\./gi ]} );

возвращает 3 для меня. При создании ссылки на массив регулярное выражение вычисляется в контексте списка и @{..} де-ссылки на ссылку массива.

является ли следующий код однострочным?

print $string =~ s/\./\./g;

другой путь,

my $string = "one.two.three.four";
@s = split /\./,$string;
print scalar @s - 1;
my $count = 0;
my $pos = -1;
while (($pos = index($string, $match, $pos+1)) > -1) {
  $count++;
}

проверено с бенчмарком, это довольно быстро

метод Фридо:$a = () = $b =~ $c.

но это можно упростить еще больше, чтобы просто ($a) = $b =~ $c, например :

my ($matchcount) = $text =~ s/$findregex/ /gi;

вы могли бы поблагодарить просто обернуть это в функцию,getMatchCount(), и не беспокойтесь об этом, уничтожая переданную строку.

С другой стороны, вы можете добавить в своп, который может быть немного больше вычислений, но не привести к изменению строки.

my ($matchcount) = $text =~ s/($findregex)//gi;