2014-09-12 15 views
5

Il seguente pezzo di codice funziona perfettamente con Perl (v5.16.2). Tuttavia, quando lo eseguo utilizzando Perl v5.8.9, si lamenta della regex seguente. Come posso riscrivere questo regex in un modo che funziona con Perl v5.8.9. (Non posso aggiornare la versione).Riscrivere un'espressione regolare ricorsiva per la versione Perl precedente

REGEX:

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 ([email protected]) { 
      die "Invalid formulas in $name: [email protected]"; 
     } 

     $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 

Uscite:

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

ERRORE:

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. 

UPDATE: Il codice viene aggiornato. Questo è stato originariamente suggerito da https://stackoverflow.com/users/1733163/miller

+2

Vorrei consigliamo di provare [perlbrew] (http://perlbrew.pl/) per installare una nuova versione di perl a livello locale. – Miller

+0

Vedere Testo :: Equilibrato – ikegami

risposta

2

Prima dell'introduzione di (?PARNO), abbiamo dovuto usare (??{ code }) per creare espressioni regolari ricorsive. Un esempio può essere trovato in perlre - Extended Patterns.

Di seguito è testata su v5.16.2, v5.20.0, e localmente su un 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 
} 

Nota, volutamente separato la dichiarazione della variabile _RE e la sua inizializzazione. Ci sono alcune versioni di perl che ti permetteranno di dichiarare un'espressione regolare ricorsiva nella stessa istruzione dell'inizializzazione, ma la v5.8.9 non è una di queste.

Inoltre, se si desidera modificare la regex originale più di una semplice sostituzione della notazione (?PARNO), è possibile ridurre quanto riportato sopra. Ha inoltre confermato il 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 
} 
+0

grazie per il vostro aiuto gentile e rapido. Faccio il codice completo (suggerito in origine da te stesso). Per favore, vai avanti e metti alla prova la tua. Ha fallito per me. Spero che tu non mi odi cambiando il codice ora. –

+0

Ecco due test di lavoro confermati: [Ideone's Perl v5.16.2] (http://ideone.com/HDw9HV) e [Eval.in's Perl v5.20.0] (https://eval.in/192526) – Miller

+0

v5.8.9? –

Problemi correlati