Perl模式与模式算法匹配

时间:2012-11-10 17:16:24

标签: regex perl

我想了解如何在perl regex中对匹配的子模式进行算术运算。 这只是一个示例代码,我想了解如何使用\1(已匹配的子模式。在这种情况下为7)来匹配pattern+1 (8)

my $y = 77668;
if($y =~ /(\d)\1(\d)\2\1+1/)   #How to increment a previously
                               #matched sub-pattern and form a pattern?
{
    print $y;
}

编辑

从答案中,我看到模式算术是不可能的。

这就是我想要实现的目标 我想形成一个匹配这种模式的正则表达式:

N-3N-2N-1NNN+1N+2N+3    (N = 3,4,5,6

2 个答案:

答案 0 :(得分:6)

当然这是可能的。毕竟我们正在谈论Perl正则表达式。但它会相当丑陋:

say "55336"=~m{(\d)\1(\d)\2(\d)(?(?{$1+1==$3})|(*F))}?"match":"fail";

或漂亮印刷:

say "55336" =~ m{  (\d)\1 (\d)\2 (\d)
                   (?  (?{$1+1==$3}) # true-branch: nothing
                                   |(*FAIL)
                   )
                }x
     ? "match" : "fail";

这是做什么的?我们收集普通捕获中的数字。最后,我们使用if-else模式:

(? (CONDITION) TRUE | FALSE )

我们可以使用(?{ code })将代码嵌入到正则表达式中。此代码的返回值可用作条件。 (*FAIL)(简称:(*F)动词会导致匹配失败。如果您只想要一个分支,请使用(*PRUNE),而不是整个模式失败。

嵌入式代码也非常适合调试。但是,较旧的perls不能在此正则表达式代码中使用正则表达式: - (

所以我们可以匹配很多东西并在模式本身内测试它的有效性。但是,可能更好的做法是在模式之外

 "string" =~ /regex/ and (conditions)

现在转到主模式N-3N-2N-1NNN+1N+2N+3(我希望正确解析它):

my $super_regex = qr{
        # N -3 N-2 N-1 N N N+1 N+2 N+3
        (\d)-3\1-2\1-1\1\1(\d)(\d)(\d)
        (?(?{$1==$2-1 and $1==$3-2 and $1==$4-3})|(*F))
    }x;

say "4-34-24-144567" =~ $super_regex ? "match" : "fail";

或者你的意思是

my $super_regex = qr{
        #N-3 N-2 N-1  N  N   N+1 N+2 N+3
        (\d)(\d)(\d) (\d)\4 (\d)(\d)(\d)
        (?  (?{$1==$4-3 and $2==$4-2 and $3==$4-1 and
               $5==$4+1 and $6==$4+2 and $7==$4+3})|(*F))
    }x;

say "123445678" =~ $super_regex ? "match" : "fail";

可怕的是,这些甚至有效(使用perl 5.12)。

我们还可以在匹配时使用(??{ code })构造生成部分模式 - 此代码的返回值用作模式:

my $super_regex = qr{(\d)(??{$1+1})(??{$1+2})}x;
say "234"=~$super_regex ? "match":"fail"

等等。但是,我认为可读性受此影响更大。

如果您需要超过9次捕获,可以使用命名捕获

(?<named>pattern) ... \k<named>

构建体。内容也可以在%+哈希中找到,请参阅perlvar。

为了进一步深入了解Perl正则表达式的秘密,我建议您多阅几次perlre

答案 1 :(得分:6)

可以通过正则表达式代码块实现:

my $y = 77668;
if($y =~ /(\d)\1(\d)\2(??{$1+1})/ ) {
    print $y;
}

在此代码段(??{ CODE })中返回另一个必须匹配的正则表达式,因此此正则表达式看起来像“8”($ 1 + 1)。因此,整个正则表达式只有在第5位数更好且第1位数为1时才匹配。但第1位数的缺点是9,此代码块将返回“10”,因此可能出现错误行为,但您没有说什么必须是在这种情况下完成。

现在关于N-3N-2N-1NNN+1N+2N+3问题,您可以将其与此正则表达式匹配:

my $n = 5;
if( $y =~ /(??{ ($n-3).($n-2).($n-1).$n.($n+1).($n+2).($n+3) })/ ){

或更“可扩展”的方式:

my $n = 5;
if( $y =~ /(??{ $s=''; $s .= $n+$_ foreach(-3..3); $s; })/ ){

同样,如果$ n == 2,我们必须做什么? $ n-3将为-1。它不是一个简单的数字cus它有标志,所以你应该考虑这种情况。

另一种方式。匹配我们所拥有的,然后检查它。

if( $y =~ /(\d)(\d)(\d)(\d)(\d)(\d)(\d)/ ) {
    if( $1 == ($4-3) && $2 == ($4-2) && $3 == ($4-1) && $6 == ($4+1) && $7 == ($4+2) && $7 == ($4+3) ) {
        #...
似乎这种方法有点笨拙,但它对所有人都很乖((我希望)。

另外,你可以优化你的正则表达式,因为7个升序数字条纹不是那么常见的组合,再加上来自同事xD的一些lulz:

sub check_number {
    my $i;
    for($i=1; $i<length($^N); $i++) {
        last if substr($^N, $i, 1)<=substr($^N, $i-1, 1);
    }
    return $i<length($^N) ? "(*FAIL)" : "(*ACCEPT)";
}

if( $y =~ /[0123][1234][2345][3456][4567][5678][6789](??{ check_number() })/ ) {

或......也许是最人性化的方法:

if( $y =~ /0123456|1234567|2345678|3456789/ ) {

似乎最后一个变种是bingo xD它是关于在事情如此简单时不搜索正则表达式的好例子。