82

假设我有:

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

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

我试过这个:

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

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

4

9 回答 9

125

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

 my $number = () = $string =~ /\./gi;
于 2009-12-04T20:09:24.980 回答
35

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

my $string = "one.two.three.four";
my @count = $string =~ /\./g;
print scalar @count;
于 2009-12-04T20:17:33.763 回答
24

另请参阅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;
于 2009-12-04T20:20:42.073 回答
9

以下代码是单行代码吗?

print $string =~ s/\./\./g;
于 2009-12-05T01:07:52.480 回答
7

试试这个:

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

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

于 2009-12-04T20:08:52.027 回答
0

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

例如:

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";

然后给出三个正确答案。

于 2019-04-02T14:41:20.057 回答
-1

其他方式,

my $string = "one.two.three.four";
@s = split /\./,$string;
print scalar @s - 1;
于 2009-12-04T23:56:44.843 回答
-1

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

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

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

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

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

my ($matchcount) = $text =~ s/($findregex)/$1/gi;
于 2015-10-23T15:13:12.757 回答
-1
my $count = 0;
my $pos = -1;
while (($pos = index($string, $match, $pos+1)) > -1) {
  $count++;
}

用 Benchmark 查了一下,速度挺快的

于 2018-05-09T00:10:44.217 回答