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

63

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

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

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

Я пробовал это:

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

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

Теги:
arrays

7 ответов

97
Лучший ответ

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

 my $number = () = $string =~ /\./gi;
  • 3
    Ну, perlsecret предлагает «Сатурн» в качестве альтернативного имени. :)
  • 0
    Может кто-нибудь объяснить мне этот кусок кода? Я новичок в Perl, и мне все еще не очень комфортно с контекстами.
32

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

my $string = "one.two.three.four";
my @count = $string =~ /\./g;
print scalar @count;
  • 13
    +1 за самый простой способ, оператор козла страшный.
  • 1
    Скобки вокруг @count не нужны.
19

Также см. 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;
7

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

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

Попробуйте следующее:


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

Он возвращает 3 для меня. Создавая ссылку на массив, регулярное выражение оценивается в контексте списка, а @{..} отменяет ссылки на ссылку массива.

  • 3
    Вам не нужно ничего из этих скобок.
  • 1
    Я должен сказать, что мне нравится этот метод лучше, чем козел. На самом деле мне нравится почти все лучше, чем козел.
0

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

Но это можно упростить еще до простого ($a) = $b =~ $c, например:

my ($matchcount) = $text =~ s/$findregex/ /gi;
  • 0
    За исключением того, что это замена, а не совпадение: она уничтожит исходную строку. И это та же идея, что и у @Mike 6 лет назад.
  • 0
    @fishinear: Это сильно отличается от Майка. Он был способен напечатать это, но не хранить его в переменной. Разница значительна.
Показать ещё 2 комментария
0

другой способ,

my $string = "one.two.three.four";
@s = split /\./,$string;
print scalar @s - 1;

Ещё вопросы

Сообщество Overcoder
Наверх
Меню