34

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

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

我无法更改正则表达式,甚至不能()像用户可能使用的那样添加它()\1. 也许我可以使用(?:).

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

4

5 回答 5

80

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

于 2008-09-17T20:54:04.070 回答
21

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

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
}

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

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

于 2008-09-17T20:47:29.157 回答
8

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
}
于 2008-09-17T20:38:53.420 回答
0

如果您愿意让程序中的所有 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".
于 2008-09-17T20:43:13.473 回答
0
#!/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"; 
}
于 2016-01-22T00:16:37.520 回答