1

我有一个(非常)长的数字字符串列表,我需要计算某些值的出现次数,以便决定是否拉出与字符串关联的行。本质上,该文件的格式如下:

,4,8,9,11,12,
,5,6,7,9,11,
etc.

其中字符串的长度范围为 1 - 100 个值,值的范围为 1 - 100,并且字符串中的值始终按从小到大的顺序排列。

我试图找到所有的行,例如,三个值 4、9 和 11 中至少有两个,所以这是我写的测试代码来尝试我的正则表达式:

my $string = ",4,8,9,11,12,";

my $test = ",4,|,9,|,11,";

my @c = $string =~ m/$test/g;
my $count = @c;

print "count: $count\n";
print "\@c:, join(" ", @c), "\n";

我运行时的输出是:

count: 2
@c:,4, ,9,

当我期望 count 是3并且 @c 是,4, ,9, ,11,.

我意识到这是因为 9 和 11 共享相同的逗号,但我想知道是否有人知道如何解决这个问题。我不能只从匹配中删除最后一个逗号,因为如果我试图匹配,4一个,41,包含例如的字符串,它会错误地计算,41,.

我想我可以做类似的事情:

my $test = "4|9|11";
$string =~ s/,/ /;
my @c = $string =~ m/\b($test)\b/g

这有效,但在匹配计数之前增加了另一个步骤。有没有办法在保持原始字符串不变的情况下执行匹配?

我还试图避免单独循环遍历我的匹配目标并将单个匹配计数相加,因为我试图最大限度地提高效率。我正在处理一些需要数百万次排列的非常庞大的值列表,而我目前使用循环编写脚本的方式需要几天时间才能完成。我希望通过正则表达式匹配它会更快。

谢谢

4

4 回答 4

3

问题是,在匹配中消耗了尾随,9,,所以当它开始寻找下一个匹配时,它从11,12,. ,在 the 之前没有领先,11,所以它不能匹配。我建议使用这样的前瞻:

,(4|9|11)(?=,)

这样,尾随,将不会作为匹配的一部分被消耗。

例如:

my $string = ",4,8,9,11,12,";

my $test = ",(4|9|11)(?=,)";

my @c = $string =~ m/$test/g;
my $count = @c;
print "count: $count\n";
print "\@c:", join(" ", @c), "\n";

输出:

count: 3
@c:4 9 11
于 2014-03-05T17:46:51.077 回答
1

忽略逗号。这可以满足您的要求:

printf "count: %d\n", scalar( () = $string =~ /\b(?:4|9|11)\b/g );

对空列表的列表分配() = ...发生在由 提供的标量上下文中scalar(),当它返回右侧列表中的元素数时。这(?:...)只是为了避免创建捕获组,这应该会提高性能。

编辑:

好的,OP 要求性能,所以我做了一些基准测试,结果证明一个简单的

++$count while ($string =~ /\b(?:4|9|11)\b/g);

比我上面的列表分配技巧更快(在我的老式笔记本电脑上加速大约 30%)和来自 pswg 的带有前瞻模式的答案(大约 20% 加速,所以他的解决方案实际上可能不那么花哨,但比我的第一个解决方案更快)。

于 2014-03-05T18:09:37.963 回答
0

我会使用以下内容而不是正则表达式:

#!/usr/bin/perl

use strict;
use warnings;

my @values = qw(4 9 11);

while (<DATA>) {
    my %hash = map { $_ => 1 } split /,/;

    my $count = 0;
    foreach my $value (@values) {
        $count++ if exists $hash{$value};
    }

    print if $count >= 2;
}

__DATA__
,4,8,9,11,12,
,5,6,7,9,11,
,1,2,3,4,5,

输出:

,4,8,9,11,12,
,5,6,7,9,11,  
于 2014-03-05T17:52:23.977 回答
0

这也适用于您,因为您在正则表达式匹配期间有重叠:

my $str = ',4,8,9,11,12,11,';
my @arr = $str =~ /(?=,(4|9|11),)/g;
于 2014-03-05T17:54:27.310 回答