我如何获得最低匹配的captureno?

时间:2012-12-03 18:10:50

标签: perl

如何在正则表达式中获得最低匹配组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**

5 个答案:

答案 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

此时,应该能够轻松地修改代码,以便为匹配的任何组做任何事情。