【发布时间】:2016-06-21 17:40:27
【问题描述】:
计算某个字符串出现在较大字符串中的次数的最快方法是什么?我最好的猜测是将该字符串的所有实例都替换为空,计算长度差并除以子字符串的长度,但这似乎相当慢,我需要分析大量数据。
【问题讨论】:
-
可能想看看这个......虽然它是从 1999 年开始的,而且很可能还有其他方法可以有效地做这种事情:perlmonks.org/…
计算某个字符串出现在较大字符串中的次数的最快方法是什么?我最好的猜测是将该字符串的所有实例都替换为空,计算长度差并除以子字符串的长度,但这似乎相当慢,我需要分析大量数据。
【问题讨论】:
您可以捕获字符串,然后计算它们。可以通过使用() 将列表上下文应用于捕获来完成:
my $x = "foo";
my $y = "foo foo foo bar";
my $c = () = $y =~ /$x/g; # $c is now 3
您还可以捕获到数组并对数组进行计数。原理相同,手法不同:
my @c = $y =~ /$x/g;
my $count = @c;
【讨论】:
my $count = @c = $y =~ /$x/g,但您可以简单地忽略@c 并使用()。如果您不关心实际匹配,那么哪个是最好的。
$x 包含某些正则表达式字符,这不起作用,因为$x 被解释为正则表达式。添加\Q 来解决这个问题,例如。 /\Q$x/g。请参阅quotemeta 了解更多信息。
my $c = () = $y =~ /$x/g 和(恕我直言)更漂亮的my $c = scalar($y =~ /$x/g) 有什么区别?我猜它们是一样的,但如果后者效率不高,我会使用前者。 (我的理解是 scalar() 呼叫不是必需的,正如下面 Brian Roach 的回答中所指出的那样。)
my $string = "aaaabbabbba";
my @count = ($string =~ /a/g);
print @count . "\n";
或
my $count = ($string =~ s/a/a/g);
【讨论】:
您可以使用全局正则表达式。比如:
my @matches = $bigstring =~ /($littlestring)/g;
my $count = @matches;
【讨论】:
为了完整起见,您可以在循环中重复调用 index 函数并计算它返回字符串中子字符串索引的所有次数,并更改起始位置。这将避免使用正则表达式,并且在我的测试中比正则表达式解决方案要快一些。
我已经从这里改编了一个子来做到这一点:http://www.misc-perl-info.com/perl-index.html
sub occurrences {
my( $x, $y ) = @_;
my $pos = 0;
my $matches = 0;
while (1) {
$pos = index($y, $x, $pos);
last if($pos < 0);
$matches++;
$pos++;
}
return $matches;
}
【讨论】: