4

我想了解如何在 perl 正则表达式中对匹配的子模式进行算术运算。这只是一个示例代码,我想了解如何使用\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
4

2 回答 2

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"

等等。但是,我认为这种方式的可读性会受到更多影响。

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

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

结构体。这些内容也可以在%+散列中找到,请参阅 perlvar 。

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

于 2012-11-10T18:46:36.033 回答
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。它不是一个简单的数字,它有符号,所以你应该考虑这种情况。

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

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 它是关于在事情如此简单时不搜索正则表达式的好例子)

于 2012-11-10T19:24:41.473 回答