以下代码可以与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 }