是否有Perl快捷方式来计算字符串中的匹配数?

时间:2009-12-04 20:04:21

标签: arrays regex perl perl4

假设我有:

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

如何使用上下文来获取模式找到匹配的次数(3)?这可以使用单线程吗?

我试过了:

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

我认为通过在$number周围放置括号,我强制使用数组上下文,并且通过使用scalar,我得到了计数。但是,我得到的只是1

9 个答案:

答案 0 :(得分:112)

这使得正则表达式本身处于标量上下文中,这不是你想要的。相反,将正则表达式置于列表上下文中(以获取匹配数)并将 放入标量上下文中。

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

答案 1 :(得分:32)

我认为描述这个的最明确的方法是避免即时转换为标量。首先分配给一个数组,然后在标量上下文中使用该数组。这基本上是= () =成语会做的,但没有(很少使用)成语:

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

答案 2 :(得分:20)

另请参阅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;

答案 3 :(得分:6)

试试这个:


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

它为我返回3。通过创建对数组的引用,在列表上下文中计算正则表达式,@{..}取消引用数组引用。

答案 4 :(得分:6)

以下代码是单行吗?

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

答案 5 :(得分:0)

我注意到,如果您的正则表达式(例如/(K..K)|(V.AK)/gi中有一个OR条件,那么生成的数组可能包含未定义的元素,这些元素都包含在末尾的计数中。

例如:

my $seq = "TSYCSKSNKRCRRKYGDDDDWWRSQYTTYCSCYTGKSGKTKGGDSCDAYYEAYGKSGKTKGGRNNR";
my $regex = '(K..K)|(V.AK)';
my $count = () = $seq =~ /$regex/gi;
print "$count\n";

给出的计数值为6。

我在这篇文章中找到了解决方案 How do I remove all undefs from array?

my $seq = "TSYCSKSNKRCRRKYGDDDDWWRSQYTTYCSCYTGKSGKTKGGDSCDAYYEAYGKSGKTKGGRNNR";
my $regex = '(K..K)|(V.AK)';
my @count = $seq =~ /$regex/gi;
@count = grep defined, @count; 
my $count = scalar @count;
print "$count\n";

然后给出正确答案为三。

答案 6 :(得分:-1)

另一种方式,

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

答案 7 :(得分:-1)

弗里多的方法是:$a = () = $b =~ $c

但是可以将其进一步简化为($a) = $b =~ $c,如下所示:

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

你可以感谢将它包装在一个函数getMatchCount()中,而不用担心它会破坏传递的字符串。

另一方面,您可以添加交换,这可能会多一些计算,但不会导致更改字符串。

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

答案 8 :(得分:-1)

my $count = 0;
my $pos = -1;
while (($pos = index($string, $match, $pos+1)) > -1) {
  $count++;
}

使用Benchmark查看,它的速度非常快