regex - probar - expresiones regulares perl online
¿Cómo acceder a los grupos capturados por expresiones regulares perl recursivas? (2)
La necesidad de tener que agregar maquinaria de captura y retroceso es una de las deficiencias que aborda Regexp::Grammars .
Sin embargo, la gramática en su pregunta es left-recursive , que ni Perex regexes ni un analizador recursivo descenderá.
Adaptar su gramática a Regexp::Grammars y factorizar la recursión izquierda produce
my $EXPR = do {
use Regexp::Grammars;
qr{
^ <Expr> $
<rule: Expr> <Term> <ExprTail>
| <Term>
<rule: Term> <Number>
| <Var>
| /( <MATCH=Expr> /)
<rule: ExprTail> <Op> <Expr>
<token: Op> /+ | /- | /* | //
<token: Number> /d++
<token: Var> [a-z]++
}x;
};
Tenga en cuenta que esta sencilla gramática otorga a todos los operadores la misma prioridad en lugar de, por favor, disculpe a My Dear Tía Sally.
Desea extraer todos los nombres de variables, por lo que podría caminar el AST como en
sub all_variables {
my($root,$var) = @_;
$var ||= {};
++$var->{ $root->{Var} } if exists $root->{Var};
all_variables($_, $var) for grep ref $_, values %$root;
wantarray ? keys %$var : [ keys %$var ];
}
e imprimir el resultado con
if ("(a + (b - c))" =~ $EXPR) {
print "[$_]/n" for sort +all_variables /%/;
}
else {
print "no match/n";
}
Otro enfoque es instalar una acción automática para la regla Var
que registra los nombres de las variables a medida que se analizan con éxito.
package JustTheVarsMaam;
sub new { bless {}, shift }
sub Var {
my($self,$result) = @_;
++$self->{VARS}{$result};
$result;
}
sub all_variables { keys %{ $_[0]->{VARS} } }
1;
Llama a este como en
my $vars = JustTheVarsMaam->new;
if ("(a + (b - c))" =~ $EXPR->with_actions($vars)) {
print "[$_]/n" for sort $vars->all_variables;
}
else {
print "no match/n";
}
De cualquier manera, la salida es
[a] [b] [c]
Estoy intentando mezclar una gramática simple con una expresión regular de perl (tenga en cuenta que esto no está destinado para uso de producción, solo un análisis rápido para proporcionar sugerencias / terminaciones de editor). Por ejemplo,
my $GRAMMAR = qr{(?(DEFINE)
(?<expr> /( (?&expr) /) | (?&number) | (?&var) | (?&expr) (?&op) (?&expr) )
(?<number> /d++ )
(?<var> [a-z]++ )
(?<op> [-+*/] )
)}x;
Me gustaría poder ejecutar esto como
$expr =~ /$GRAMMAR(?&expr)/;
y luego acceder a todos los nombres de variables. Sin embargo, según el perlre ,
Tenga en cuenta que los grupos de captura coincidentes dentro de la recursión no son accesibles después de que la recursión regrese, por lo que es necesario el nivel adicional de los grupos de captura. Por lo tanto, $ + {NAME_PAT} no se definiría a pesar de que $ + {NAME} sí lo estaría.
Así que aparentemente esto no es posible. Podría intentar usar un bloque (?{ code })
para guardar los nombres de las variables en un hash, pero esto no respeta el seguimiento (es decir, el efecto secundario de la asignación persiste incluso si la variable está pasada atrás).
¿Hay alguna forma de obtener todo lo capturado por un grupo de captura con nombre dado, incluidas las coincidencias recursivas? ¿O necesito cavar manualmente a través de las piezas individuales (y así duplicar todos los patrones)?
La recursividad es nativa con Marpa :: R2 utilizando el BNF en la sección __DATA__ a continuación:
#!env perl
use strict;
use diagnostics;
use Marpa::R2;
my $input = shift || ''(a + (b - c))'';
my $grammar_source = do {local $/; <DATA>};
my $recognizer = Marpa::R2::Scanless::R->new
(
{
grammar => Marpa::R2::Scanless::G->new
(
{
source => /$grammar_source,
action_object => __PACKAGE__,
}
)
},
);
my %vars = ();
sub new { return bless {}, shift;}
sub varAction { ++$vars{$_[1]}};
$recognizer->read(/$input);
$recognizer->value() || die "No parse";
print join('', '', sort keys %vars) . "/n";
__DATA__
:start ::= expr
expr ::= NUMBER
| VAR action => varAction
| expr OP expr
| ''('' expr '')''
NUMBER ~ [/d]+
VAR ~ [a-z]+
OP ~ [-+*/]
WS ~ [/s]+
:discard ~ WS
La salida es:
a, b, c
Su pregunta se dirigía solo a cómo obtener los nombres de las variables, por lo que no hay noción de asociatividad del operador, etc. en esta respuesta. Solo tenga en cuenta que Marpa no tiene ningún problema con eso, si es necesario.