加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

为旧的Perl版本重写递归正则表达式

发布时间:2020-12-15 23:34:04 所属栏目:大数据 来源:网络整理
导读:以下代码可以与Perl(v5.16.2)一起使用.但是,当我使用Perl v5.8.9运行它时,它会抱怨以下正则表达式.如何以与Perl v5.8.9一起使用的方式重写此正则表达式. (我无法更新版本). 正则表达式: use strict;use warnings;our %formula_per_k;INIT { # List all func
以下代码可以与Perl(v5.16.2)一起使用.但是,当我使用Perl v5.8.9运行它时,它会抱怨以下正则表达式.如何以与Perl v5.8.9一起使用的方式重写此正则表达式. (我无法更新版本).

正则表达式:

use strict;
use warnings;

our %formula_per_k;
INIT {
    # List all functions that you want to allow in formulas.  All other words will be interpretted as variables.
    my @FORMULA_FUNCS = qw(sqrt exp log);

    # Load the data via a file.
    my $data = do {local $/; <DATA>};

    # Parse K blocks
    while ($data =~ m{
        ^K s+ (w+) s* {
            ( (?: [^{}]+ | {(?2)} )* )         # Matched braces only.
        }
    }mgx) {
        my ($name,$params) = ($1,$2);

        # Parse LOL block
        next if $params !~ m{
            LOL s* { 
                ( (?: [^{}]+ | {(?1)} )*? )    # Matched braces only.
            }
        }mx;
        my $lol = $1;

        # Start building anonymous subroutine
        my $conditions = '';

        # Parse Conditions and Formulas
        while ($lol =~ m{
            COND s* { (.*?) } s* 
            FORMULA s* { (.*?) }
        }gx) {
            my ($cond,$formula) = ($1,$2);

            # Remove Excess spacing and translate variable into perl scalar.
            for ($cond,$formula) {
                s/^s+|s+$//g;
                s{([a-zA-Z]+)}{
                    my $var = $1;
                    $var = "$hashref->{$var}" if ! grep {$var eq $_} @FORMULA_FUNCS;
                    $var
                }eg;
            }

            $conditions .= "return $formula if $cond; ";
        }

        my $code = "sub {my $hashref = shift; ${conditions} return; }";

        my $sub = eval $code;
        if ($@) {
            die "Invalid formulas in $name: $@";
        }

        $formula_per_k{$name} = $sub;
    }
}

sub formula_per_k {
    my ($k,$vars) = @_;

    die "Unrecognized K value '$k'" if ! exists $formula_per_k{$k};

    return $formula_per_k{$k}($vars);
}

print "'K1',{d => .1}   = " . formula_per_k('K1',{d => .1}) . "n";
print "'K1',{d => .05}  = " . formula_per_k('K1',{d => .05}) . "n";
print "'K3',{d => .02}  = " . formula_per_k('K3',{d => .02}) . "n";
print "'K3',{d => .021} = " . formula_per_k('K3',{d => .021}) . "n";


__DATA__
... #OTHER STUFFS
K K1 {
    LOL {
        COND { d < 0.01 }
        FORMULA { -0.2 + 3.3*sqrt(d) }
        COND { d >= 0.01 }
        FORMULA { -0.2 + 3.3*sqrt(d+0.4) }
    }
}
... #OTHER STUFFS
K K2 {
    LOL {
        COND { d < 0.03 }
        FORMULA { -2.2 + 1.3*sqrt(d) }
        COND { d >= 0.03 }
        FORMULA { -2.2 + 1.3*sqrt(d+0.8) }
    }
}
... #OTHER STUFFS
K K3 {
    LOL {
        COND { d < 0.02 }
        FORMULA { -4.3 + 0.3*sqrt(d) }
        COND { d >= 0.02 }
        FORMULA { -4.3 + 0.3*sqrt(d+0.3) }
    }
}
... #OTHER STUFF

输出:

'K1',{d => .1}   = 2.13345237791561
'K1',{d => .05}  = 2.01370729772479
'K3',{d => .02}  = -4.13029437251523
'K3',{d => .021} = -4.13002941430942

错误:

Sequence (?1...) not recognized in regex; marked by <-- HERE in m/
            ^K s+ M3 s* {
                ( (?: [^{}]+ | {(?2 <-- HERE )} )* )         # Matched braces only.
            }
        / at ./code.pl line 215,<RFILE> line 12.

更新:
代码已更新.
这最初是由https://stackoverflow.com/users/1733163/miller提出的

解决方法

在引入(?PARNO)之前,我们必须使用(?? {code})来创建递归正则表达式.一个例子可以在 perlre – Extended Patterns找到.

以下是在v5.16.2,v5.20.0和本地v5.8.9 perlbrew上测试的:

our $braces_re;
$braces_re = qr{
    {
    (?:
        (?> [^{}]+ )
    |
        (??{ $braces_re })
    )*
    }
}sx;

# parse FOO block
while (
    $data =~ m{
    ^FOO s+ (w+) s* {
        ( (?: [^{}]+ | (??{ $braces_re }) )* )         # Matched braces only.
    }
}mgx
    )
{
    my $params = $1;

    # parse BAR block
    next if $params !~ m{
        BAR s* { 
            ( (?: [^{}]+ | (??{ $braces_re }) )*? )    # Matched braces only.
        }
    }mx;
    # SOME CODE
}

注意,我故意将_re变量的声明和它的初始化分开.有一些perl版本可以让你在与初始化相同的语句中声明一个递归正则表达式,但v5.8.9不是其中之一.

此外,如果您只是简单地替换(?PARNO)符号来改变原始正则表达式,那么上述内容可以简化为以下内容.也于v5.16.2确认:

my $braces_re;
$braces_re = qr{
    (?:
        (?> [^{}]+ )
    |                                   # The following is a "postponed" regular subexpression.
        { (??{ $braces_re }) }        # Deferred execution enables recursive regex
    )*
}sx;

# parse FOO block
while ( $data =~ m{^FOO s+ (w+) s* { ( $braces_re ) } }mgx ) {
    my $params = $1;

    # parse BAR block
    next if $params !~ m{BAR s* { ( $braces_re ) }}mx;
    # SOME CODE
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读