sub countnmstr
{
my ($string, $substr) = @_;
return scalar( () = $string =~ /(?=\Q$substr\E)/g );
}
$count = countnmstr("aaa","aa");
print "$count\n";
Несколько баллов:
//g
в контексте списка совпадает столько раз, сколько возможно.
\Q...\E
используется для автоматического экранирования любых метасимволов, поэтому вы выполняете подсчет подстрок, а не подсчет подшаблонов.
Использование заглядывания (?= ... )
приводит к тому, что каждое совпадение не "потребляет" ни одной строки, что позволяет выполнить следующее сопоставление на следующем символе.
При этом используется та же функция, при которой назначение списка (в данном случае пустому списку) в скалярном контексте возвращает количество элементов справа от назначения списка как goatse / flying-lentil / spread-eagle / what оператор, но использует scalar () вместо скалярного присваивания для предоставления скалярного контекста.
$_[0]
не используется напрямую, а вместо этого копируется в лексическое; наивное использование $_[0]
вместо $string
приведет к тому, что //g
будет начинаться частично через строку, а не с начала, если переданная строка имела сохраненный pos()
.
Обновление: s /// g быстрее, но не так быстро, как при использовании индекса:
sub countnmstr
{
my ($string, $substr) = @_;
return scalar( $string =~ s/(?=\Q$substr\E)//g );
}