Perl - 正则表达式 - 第一个不匹配字符的位置

时间:2011-10-10 11:48:21

标签: regex perl position pattern-matching

我想在字符串中找到位置,正则表达式停止匹配。

简单示例:

my $x = 'abcdefghijklmnopqrstuvwxyz';
$x =~ /gho/;

这个例子给我字符'h'的位置,因为'h'匹配而'o'是第一个不匹配的字符。

我想过使用pos或$ - 但它不会写在不成功的匹配上。 另一个解决方案是迭代缩短正则表达式模式,直到它匹配,但这非常难看,并且不适用于复杂的模式。

编辑:

好的语言学家:对不起我的糟糕解释。

澄清我的情况:如果你认为正则表达式是一个有限自动机,那么测试就会中断,因为一个字符不适合。这一点是我正在寻找的。

使用迭代paranthesis(如eugene y所述)是一个不错的主意,但它不适用于量词,我必须编辑模式。

还有其他想法吗?

5 个答案:

答案 0 :(得分:4)

您可以获取匹配的部分,并使用index函数查找其位置:

my $x = 'abcdefghijklmnopqrstuvwxyz';

$x =~ /(g(h(o)?)?)/;
print index($x, $1) + length($1), "\n"; #8

答案 1 :(得分:4)

你提出的建议很难,但doable

如果我可以解释我理解的内容,那么你就想知道一场失败的比赛进入比赛的程度。为此,您需要能够解析正则表达式。

最好的正则表达式解析器可能是使用Perl本身和-re=debug命令行开关:

$ perl -Mre=debug -e'"abcdefghijklmnopqr"=~/gh[ijkl]{5}/'
Compiling REx "gh[ijkl]{5}"
Final program:
   1: EXACT <gh> (3)
   3: CURLY {5,5} (16)
   5:   ANYOF[i-l][] (0)
  16: END (0)
anchored "gh" at 0 (checking anchored) minlen 7 
Guessing start of match in sv for REx "gh[ijkl]{5}" against "abcdefghijklmnopqr"
Found anchored substr "gh" at offset 6...
Starting position does not contradict /^/m...
Guessed: match at offset 6
Matching REx "gh[ijkl]{5}" against "ghijklmnopqr"
   6 <bcdef> <ghijklmnop>    |  1:EXACT <gh>(3)
   8 <defgh> <ijklmnopqr>    |  3:CURLY {5,5}(16)
                                  ANYOF[i-l][] can match 4 times out of 5...
                                  failed...
Match failed
Freeing REx: "gh[ijkl]{5}"

你可以用你的正则表达式填充Perl命令行并解析stdout的返回。寻找`

这是匹配的正则表达式:

$ perl -Mre=debug -e'"abcdefghijklmnopqr"=~/gh[ijkl]{3}/'
Compiling REx "gh[ijkl]{3}"
Final program:
   1: EXACT <gh> (3)
   3: CURLY {3,3} (16)
   5:   ANYOF[i-l][] (0)
  16: END (0)
anchored "gh" at 0 (checking anchored) minlen 5 
Guessing start of match in sv for REx "gh[ijkl]{3}" against "abcdefghijklmnopqr"
Found anchored substr "gh" at offset 6...
Starting position does not contradict /^/m...
Guessed: match at offset 6
Matching REx "gh[ijkl]{3}" against "ghijklmnopqr"
   6 <bcdef> <ghijklmnop>    |  1:EXACT <gh>(3)
   8 <defgh> <ijklmnopqr>    |  3:CURLY {3,3}(16)
                                  ANYOF[i-l][] can match 3 times out of 3...
  11 <ghijk> <lmnopqr>       | 16:  END(0)
Match successful!
Freeing REx: "gh[ijkl]{3}"

您需要构建一个可以从Perl re调试器处理the return的解析器。当正则表达式引擎试图匹配时,左手和右手角度括号显示到字符串的距离。

这不是一个简单的项目......

答案 2 :(得分:1)

这似乎有效。基本上这个想法是将正则表达式分成它的组成部分并按顺序尝试它们,返回最后一个匹配位置。需要拆分固定的字符串,但字符类和量词可以保持在一起。

理论上这应该有效,但可能需要调整。

use v5.10;
use strict;
use warnings;

my $string = 'abcdefghijklmnopqrstuvwxyz';
my $match  = partial_match($string, qw(g h (?=i) [ijkx]+ [lmn]+ z));
say "match ended at pos $match, character ", substr($string,$match,1);

sub partial_match {
    my $string = shift;
    my @rx = @_;
    my $pos;
    if ($string =~ /$rx[0]/g) {
        $pos = pos $string;
        if (defined $rx[1]) {
            splice @rx, 0, 2, $rx[0] . $rx[1];
            $pos = partial_match($string, @rx) // $pos;
        } else { return $pos }
    } else {
        say "Didn't match $rx[0]";
        return;
    }
}

答案 3 :(得分:0)

怎么样:

#!/usr/bin/perl 
use Modern::Perl;

my $x = 'abcdefghijklmnopqrstuvwxyz';
my $s = 'gho';
do {
    if ($x =~ /$s/) {
        say "$s matches from $-[0] to $+[0]";
    } else {
        say "$s doesn't match";
    }
} while chop $s;

<强>输出:

gho doesn't match
gh matches from 6 to 8
g matches from 6 to 7
 matches from 0 to 0

答案 4 :(得分:0)

我认为这正是pos函数的用途。注意:pos仅在您使用/g标记

时才有效
my $x = 'abcdefghijklmnopqrstuvwxyz';
my $end = 0;
if( $x =~ /$ARGV[0]/g )
{
    $end = pos($x);
}
print "End of match is: $end\n";

提供以下输出

[@centos5 ~]$ perl x.pl
End of match is: 0
[@centos5 ~]$ perl x.pl def
End of match is: 6
[@centos5 ~]$ perl x.pl xyz
End of match is: 26
[@centos5 ~]$ perl x.pl aaa
End of match is: 0
[@centos5 ~]$ perl x.pl ghi
End of match is: 9