【问题标题】:How can I find the location of a regex match in Perl?如何在 Perl 中找到正则表达式匹配的位置?
【发布时间】:2010-09-10 09:14:06
【问题描述】:

我需要编写一个接收字符串和正则表达式的函数。我需要检查是否有匹配并返回匹配的开始和结束位置。 (正则表达式已经由qr//编译。)

该函数可能还会收到一个“全局”标志,然后我需要返回所有匹配项的 (start,end) 对。

我无法更改正则表达式,甚至无法在其周围添加(),因为用户可能会使用()\1。也许我可以使用(?:)

示例:给定“ababab”和正则表达式qr/ab/,在全局情况下,我需要取回 3 对(开始,结束)。

【问题讨论】:

标签: regex perl


【解决方案1】:

内置变量@-@+ 分别保存最后一次成功匹配的开始和结束位置。 $-[0]$+[0] 对应于整个模式,而 $-[N]$+[N] 对应于 $N$1$2 等)子匹配。

【讨论】:

  • 请注意,$+[0] 等(“结束位置”)给出了匹配跟随字符的索引,而不是匹配本身的最后一个字符。
【解决方案2】:

忘记我之前的帖子,我有一个更好的主意。

sub match_positions {
    my ($regex, $string) = @_;
    return if not $string =~ /$regex/;
    return ($-[0], $+[0]);
}
sub match_all_positions {
    my ($regex, $string) = @_;
    my @ret;
    while ($string =~ /$regex/g) {
        push @ret, [ $-[0], $+[0] ];
    }
    return @ret
}

这种技术不会以任何方式改变正则表达式。

编辑添加:从 perlvar 引用 $1..$9。 “这些变量都是只读的,并且动态地作用于当前BLOCK。”也就是说,如果你想使用$1..$9,你不能使用子程序来进行匹配。 p>

【讨论】:

  • 您可以使用子例程进行匹配,但是您想要捕获必须使用 substr()、@- 和 @+ 来提取匹配并将它们返回给用户。
  • 正确,但这是一个特殊的 PITA。
  • 您的 match_positions 函数在其中一个可能的分支中返回 undef,在其余情况下返回一个数组。真的好吗?
【解决方案3】:

pos 函数为您提供匹配的位置。如果您将正则表达式放在括号中,您可以使用length $1 获得长度(以及结尾)。像这样

sub match_positions {
    my ($regex, $string) = @_;
    return if not $string =~ /($regex)/;
    return (pos($string) - length $1, pos($string));
}
sub all_match_positions {
    my ($regex, $string) = @_;
    my @ret;
    while ($string =~ /($regex)/g) {
        push @ret, [pos($string) - length $1, pos($string)];
    }
    return @ret
}

【讨论】:

  • 这看起来完全不正确。而不是 pos ,在 all_match_positions 中使用 pos($string) ,在另一种情况下, match_positions 它根本不起作用
  • return if not $string =~ /($regex)/; 使您无法以正确的结果调用 pos($string)
【解决方案4】:

如果您愿意让程序中的所有 RE 执行得更慢,您也可以使用已弃用的 $` 变量。来自 perlvar:

   $‘      The string preceding whatever was matched by the last successful pattern match (not
           counting any matches hidden within a BLOCK or eval enclosed by the current BLOCK).
           (Mnemonic: "`" often precedes a quoted string.)  This variable is read-only.

           The use of this variable anywhere in a program imposes a considerable performance penalty
           on all regular expression matches.  See "BUGS".

【讨论】:

    【解决方案5】:
    #!/usr/bin/perl
    
    # search the postions for the CpGs in human genome
    
    sub match_positions {
        my ($regex, $string) = @_;
        return if not $string =~ /($regex)/;
        return (pos($string), pos($string) + length $1);
    }
    sub all_match_positions {
        my ($regex, $string) = @_;
        my @ret;
        while ($string =~ /($regex)/g) {
            push @ret, [(pos($string)-length $1),pos($string)-1];
        }
        return @ret
    }
    
    my $regex='CG';
    my $string="ACGACGCGCGCG";
    my $cgap=3;    
    my @pos=all_match_positions($regex,$string);
    
    my @hgcg;
    
    foreach my $pos(@pos){
        push @hgcg,@$pos[1];
    }
    
    foreach my $i(0..($#hgcg-$cgap+1)){
    my $len=$hgcg[$i+$cgap-1]-$hgcg[$i]+2;
    print "$len\n"; 
    }
    

    【讨论】:

      猜你喜欢
      • 2012-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-29
      • 1970-01-01
      • 2017-01-03
      相关资源
      最近更新 更多