我需要在perl中实现一个程序来计算字符串中子字符串的出现次数。我按如下方式实现了它
sub countnmstr
{
$count =0;
$count++ while $_[0] =~ /$_[1]/g;
return $count;
}
$count = countnmstr("aaa","aa");
print "$count\n";这就是我通常会做的事情。然而,在上面的实现中,我想要计算'aa‘在'aaa’中的出现次数。这里我得到的答案是1,这似乎是合理的,但我也需要考虑重叠的情况。因此,上面的情况应该给出一个答案为2,因为如果我们考虑重叠,则有两个‘aa’。
有没有人能建议如何实现这样的功能?
发布于 2010-01-22 09:21:48
每个人的答案都变得相当复杂(哦!daotoad应该把他的评论作为答案!),也许是因为他们害怕goatse操作员。我没给它起名字,这只是人们的叫法。它使用的技巧是列表赋值的结果是右侧列表中元素的数量。
用于计算匹配的Perl惯用法是:
my $count = () = $_[0] =~ /($pattern)/g;goatse部分是= () =,它是两个赋值中间的一个空列表。山羊的左边部分从山羊的右边得到伯爵。请注意,您需要在模式中捕获,因为这是匹配操作符将在列表上下文中返回的列表。
现在,在你的例子中的下一个技巧是,你真的想要一个积极的后顾之忧(或者可能是前瞻)。lookarounds不使用字符,因此您不需要跟踪位置:
my $count = () = 'aaa' =~ /((?<=a)a)/g;你的aaa只是一个例子。如果你有一个可变宽度的模式,你必须使用前视。Perl中的Lookbehinds必须是固定宽度的。
发布于 2010-01-22 17:48:42
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/任意操作符,但使用scalar()而不是标量赋值来提供标量上下文。
$_[0]不是直接使用的,而是复制到词法中;如果简单地使用$_[0]代替$string,如果传递的字符串具有存储的pos(),则会导致//g从字符串的中途开始,而不是从开头开始。
更新:s/g更快,尽管不如使用index快:
sub countnmstr
{
my ($string, $substr) = @_;
return scalar( $string =~ s/(?=\Q$substr\E)//g );
}发布于 2010-01-22 09:10:41
您可以在正则表达式中使用lookahead assertion:
sub countnmstr {
my @matches = $_[0] =~ /(?=($_[1]))/g;
return scalar @matches;
}不过,我怀疑西南的建议会更快。
https://stackoverflow.com/questions/2114185
复制相似问题