如何在正则表达式中获得最低匹配组no?
假设有正则表达式
/(a(b))|(b(1))|(c(4))/...
例如输入字符串为“b1”,最低匹配组为2($ 2)
例如输入字符串为“c4”,最低匹配组为5($ 5)
例如输入字符串为“ab”,最低匹配组为1($ 1)
我有一个解决方案,但效率不高。 Thakns都是为了尝试。 真正的问题是效率。许多人提供了类似的解决方案。 问题是搜索最低组的线性时间。 O(N)其中n是捕获基团的数量。 我想知道是否有更快的方法。 O(1)这就是这个问题的目的。 我希望Perl有一个隐藏的功能来获得该值。我想没有。
与此同时,我自己找到了解决方案,这里是..
/(a(b)(?? {$ first = 1;“”}))|(b(1)(?? {$ first = 2;“”}))|(c(4)( ?? {$ first = 5;“”}))/
首先找出$的时间是O(1)。
if (@matches = $conv::content =~/$conv::trtree{convertsourceregqr}[$conversionno]/)
{
my $firstno;
my $c = 0;
for my $m (@matches)
{
if (defined $m)
{
$firstno=$c;
last;
}
$c++;
}**strong text****strong text**
答案 0 :(得分:4)
这与您的问题不符,但它可能会解决您的实际问题(或者未来的读者)。
编辑(12/10/12):
还有一个选项,the special construct (?|)
将重新组织替换中的编号,以便数字保持一致。这无法确定哪个群组匹配,但会确保匹配位于$1
和$2
。如果你需要知道哪些匹配的,命名的捕获(下面)是要走的路。
#!/usr/bin/env perl
use strict;
use warnings;
foreach my $v ('ab', 'b1', 'c4') {
print "Input: $v\n";
next unless $v =~ /(?|(a(b))|(b(1))|(c(4)))/;
print "$1 => $2\n";
}
<强>原始强>
也许您想使用named captures来减轻理解匹配内容的负担。命名捕获结果放在%+
哈希中,因此更容易内省。
#!/usr/bin/env perl
use strict;
use warnings;
foreach my $v ('ab', 'b1', 'c4') {
print "Input: $v\n";
next unless $v =~ /(?<a>a(?<ab>b))|(?<b>b(?<b1>1))|(?<c>c(?<c4>4))/;
foreach my $key (sort keys %+) {
next unless defined $+{$key};
print "\t$key => $+{$key}\n";
}
}
打印
Input: ab
a => ab
ab => b
Input: b1
b => b1
b1 => 1
Input: c4
c => c4
c4 => 4
修改强>
事实上,对于像这样的替代,也许您只想使用重复名称!
#!/usr/bin/env perl
use strict;
use warnings;
foreach my $v ('ab', 'b1', 'c4') {
print "Input: $v\n";
next unless $v =~ /(?<outer>a(?<inner>b))|(?<outer>b(?<inner>1))|(?<outer>c(?<inner>4))/;
print "\touter => $+{outer}\n";
print "\tinner => $+{inner}\n";
}
打印
Input: ab
outer => ab
inner => b
Input: b1
outer => b1
inner => 1
Input: c4
outer => c4
inner => 4
答案 1 :(得分:2)
将匹配项存储在数组中,并找到第一个定义值的索引:
my $str = 'c4';
my @matches = ( $str =~ m/(a(b))|(b(1))|(c(4))/ );
for my $i ( 0..$#matches ) {
if ( defined $matches[$i] ) {
printf "First matching group: %d\n", $i+1;
last;
}
}
# output: 5
请注意,这将永远不会输出2,4或6,因为第1,3或5组必须匹配其中一个才能匹配。
如果您只想要第一个匹配组的内容:
use List::Util 'first';
my $str = 'c4';
print first { defined } $str =~ m/(a(b))|(b(1))|(c(4))/;
答案 2 :(得分:1)
特殊变量@-
and @+
包含成功匹配的开始和结束位置。问题的实际应用是,如果$<n>
保留一些价值($<n>
中的$1
,$2
等),那么$+[<n>]
会更大比$-[<n>]
。
for ('b1', 'c4', 'ab') {
/(a(b))|(b(1))|(c(4))/;
my @i = grep { $+[$_] > $-[$_] } 1..$#+;
# @i contains list of successful matches,
# i.e., if @i == (3,4), then $3 and $4 contain values
if (@i > 0) {
print "Earliest match for '$_' is: \$$i[0]\n";
} else {
print "No match for '$_'\n";
}
}
答案 3 :(得分:1)
首先,使用圆括号是令人困惑的。解决这个特殊问题的最简单方法是使用一个:
/(ab|b1|c4)/
由于其他括号在这种特殊情况下不起作用,因此可行。
但是,有时可能需要进行分组,在这种情况下,您可以使用非捕获括号,只使用一个来捕获(?: ... )
。在你的情况下,它看起来像这样:
/((?:a(?:b))|(?:b(?:1))|(?:c(?:4)))/
答案 4 :(得分:0)
正则表达式中的组编号是parens的数量。
1 2 3 4 5 6
/(a(b))|(b(1))|(c(4))/
用于演示此内容的快速脚本:
#!/usr/bin/perl
foreach my $v ('ab', 'b1', 'c4') {
$v =~ /(a(b))|(b(1))|(c(4))/;
if(defined $1) { print "One!\n"; }
if(defined $3) { print "Three!\n"; }
if(defined $5) { print "Five!\n"; }
print << "--EOB--";
$v
1 $1
2 $2
3 $3
4 $4
5 $5
6 $6
--EOB--
}
产生输出:
One!
ab
1 ab
2 b
3
4
5
6
Three!
b1
1
2
3 b1
4 1
5
6
Five!
c4
1
2
3
4
5 c4
6 4
此时,应该能够轻松地修改代码,以便为匹配的任何组做任何事情。