Regex 在使用多个可能的匹配目标时,如何计算perl中的正则表达式匹配|&引用;?
我有一个(非常)长的数字字符串列表,我需要计算某些值的出现次数,以决定是否拉字符串关联的线。基本上,文件的格式如下:Regex 在使用多个可能的匹配目标时,如何计算perl中的正则表达式匹配|&引用;?,regex,perl,alternation,Regex,Perl,Alternation,我有一个(非常)长的数字字符串列表,我需要计算某些值的出现次数,以决定是否拉字符串关联的线。基本上,文件的格式如下: ,4,8,9,11,12, ,5,6,7,9,11, etc. ,(4|9|11)(?=,) 其中字符串的长度范围为1-100个值,值的范围为1-100,字符串中的值始终按从最小到最大的顺序排列 例如,我试图找到三个值中至少有两个值为4、9和11的所有行,下面是我编写的测试代码,用于测试我的正则表达式: my $string = ",4,8,9,11,12,"; my $t
,4,8,9,11,12,
,5,6,7,9,11,
etc.
,(4|9|11)(?=,)
其中字符串的长度范围为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,
当我期望计数为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
这是可行的,但在匹配计数之前添加了另一个步骤。有没有办法在保持原始字符串不变的情况下执行匹配
我还试图避免逐个循环遍历我的比赛目标,并对单个比赛计数求和,因为我试图最大限度地提高效率。我正在处理一些非常庞大的值列表,这些值需要数百万次排列,而我目前使用循环编写脚本的方式需要几天才能完成。我希望通过正则表达式匹配它会更快
谢谢问题是尾随的
,
在,9,
匹配中被消耗,因此当它开始寻找下一个匹配时,它从11,12,
开始。在11,
之前没有前导的,
,所以它不能匹配。我建议使用如下前瞻:
,4,8,9,11,12,
,5,6,7,9,11,
etc.
,(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
问题是尾随的
,
在,9,
匹配中使用,因此当它开始寻找下一个匹配时,它从11,12,
开始。在11,
之前没有前导的,
,所以它不能匹配。我建议使用如下前瞻:
,4,8,9,11,12,
,5,6,7,9,11,
etc.
,(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
我将使用以下内容而不是正则表达式:
#!/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,
我将使用以下内容而不是正则表达式:
#!/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,
这一项也适用于您,因为您在正则表达式匹配过程中有重叠:
my $str = ',4,8,9,11,12,11,';
my @arr = $str =~ /(?=,(4|9|11),)/g;
这一项也适用于您,因为您在正则表达式匹配过程中有重叠:
my $str = ',4,8,9,11,12,11,';
my @arr = $str =~ /(?=,(4|9|11),)/g;
忽略逗号。这正是您想要的:
printf "count: %d\n", scalar( () = $string =~ /\b(?:4|9|11)\b/g );
空列表的列表赋值()=…
发生在标量上下文中,由scalar()
提供,当它返回右侧列表中的元素数时。
(?:…)
只是为了避免创建捕获组,这样可以提高性能
编辑:
好的,OP要求性能,所以我做了一些基准测试,结果是一个简单的
++$count while ($string =~ /\b(?:4|9|11)\b/g);
比我上面的列表分配技巧(在我古老的笔记本电脑上大约30%的加速)和p.s.w.g使用前瞻模式的答案(大约20%的加速,所以他的解决方案实际上可能没有我的第一个解决方案那么新奇,但比我的第一个解决方案快)。只需忽略逗号即可。这正是您想要的:
printf "count: %d\n", scalar( () = $string =~ /\b(?:4|9|11)\b/g );
空列表的列表赋值()=…
发生在标量上下文中,由scalar()
提供,当它返回右侧列表中的元素数时。
(?:…)
只是为了避免创建捕获组,这样可以提高性能
编辑:
好的,OP要求性能,所以我做了一些基准测试,结果是一个简单的
++$count while ($string =~ /\b(?:4|9|11)\b/g);
比我上面的列表作业技巧(在我古老的笔记本电脑上的加速率约为30%)和p.s.w.g使用前瞻模式的答案(加速率约为20%,因此他的解决方案实际上可能没有我的第一个解决方案那么新奇,但比我的第一个解决方案快)。谢谢。这个解决方案非常有效,正是我想要的。谢谢。这个解决方案工作得很好,正是我想要的。感谢您提供有关
(?:…)
的提示。我所能做的任何改进脚本性能的事情都会有所帮助,但我不知道这一点。@user3091283:我已经编辑了我的答案,以获得显著的性能改进。感谢您提供有关(?:…)
的提示。我所能做的任何改进脚本性能的事情都会有所帮助,但我不知道这一点。@user3091283:我已经编辑了我的答案,以获得显著的性能改进。