• Publicidad

(?(DEFINE)...) y recursividad en expresión regular

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

(?(DEFINE)...) y recursividad en expresión regular

Notapor pablgonz » 2016-05-06 16:18 @721

Hola a todos nuevamente. Estoy tratando de capturar una serie de listas de un archivo latex, de la forma:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. \begin{itemize}[algo]
  2.  
  3.       \item a
  4.       \item b
  5.       \item c
  6.  
  7.      \begin{itemize}
  8.        \item d
  9.        \item e
  10.      \end{itemize}
  11.  
  12.        \item f
  13.        \item g
  14.  
  15. \end{itemize}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
definidas por \begin{itemize}...\end{itemize} y dejarlas dentro de Corta ... Aqui. Como las marcas que busco pueden estar unas dentro de otras y, de ser así, siempre están balanceadas, he tratado de capturarlas con una expresión regular recursiva usando ?(DEFINE), pero, no logro dar con los cuantificadores correctos para los casos en los que aparecen estas listas.

Este es el código que he intentado:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use autodie;    # muere si ocurre un error
  4. use Data::Dumper;
  5. my $archivo = '
  6. Caso 1 (sin líneas en blanco)
  7. \begin{itemize}
  8.      \item a
  9.      \item b
  10.      \item c
  11. \end{itemize}
  12.  
  13. Caso 2 (con líneas en blanco)
  14. \begin{itemize}
  15.    
  16.      \item a
  17.      \item b
  18.      \item c
  19.  
  20. \end{itemize}
  21.  
  22. Caso 3
  23.  
  24. \begin{itemize}
  25. \begin{itemize}
  26.      \item a
  27.      \item b
  28.      \item c
  29. \end{itemize}
  30. \end{itemize}
  31.  
  32. Caso 3a
  33.  
  34. \begin{itemize}
  35.  
  36. \begin{itemize}
  37.      \item a
  38.      \item b
  39.      \item c
  40. \end{itemize}
  41.  
  42. \end{itemize}
  43.  
  44. Caso 4
  45. \begin{itemize}[algo]
  46.      \item a
  47.      \item b
  48.      \item c
  49.     \begin{itemize}
  50.       \item d
  51.       \item e
  52.     \end{itemize}
  53.       \item f
  54.       \item g
  55. \end{itemize}
  56.  
  57. Caso 5
  58. \begin{itemize}[algo]
  59.  
  60.      \item a
  61.      \item b
  62.      \item c
  63.  
  64.     \begin{itemize}
  65.       \item d
  66.       \item e
  67.     \end{itemize}
  68.  
  69.       \item f
  70.       \item g
  71.  
  72. \end{itemize}
  73. ';
  74.  
  75. # ExpReg pasada a /qr
  76. my $regex = qr/
  77.         ((?&LISTA))                      # captura
  78.         (?(DEFINE)                       # Verbo que inicia la expresión regular
  79.         (?<LISTA>                        # comenzamos con la búsqueda
  80.                 \\begin\{itemize\}\s*    # inicio del bloque deseado
  81.                         .+?
  82.                 (?&ENVCODE)?             # recursiva
  83.                         .+?
  84.                 \\end\{itemize\}(?:\s*)? # fin del bloque deseado
  85.         )                                # cierra LISTA
  86.   (?<ENVCODE> (?:(?&LISTA)).+ )  # Aplicamos la recursividad
  87. )
  88. /mx;
  89. $archivo =~ s/($regex)/Corta\n($1)Aqui\n/gmsx;
  90. say "$1";
  91.  
  92. __END__
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Agradecido.
Pablo
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)

Publicidad

Re: (?(DEFINE)...) y recursividad en expresión regular

Notapor pablgonz » 2016-05-07 15:16 @677

Encontré una solución parcial a lo que busco, con el módulo Regexp::Common se puede lograr (más menos) lo que deseo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use Regexp::Common qw /balanced/;
  2. my $regex = qr/$RE{balanced}{-begin => "\\begin\{itemize\}"}{-end => "\\end\{itemize\}"}/;
  3. $archivo =~ s/$regex/Cortar\n$1\nAqu\n/gmxs;
  4. say "$archivo";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
pero, me corta las palabras de inicio
Sintáxis: [ Descargar ] [ Ocultar ]
  1. \bCortar 
  2. egin 

Probé escapando la barra diagonal inversa, usando quotemeta y con comillas simples sin resultado positivo, observé el código del módulo y me percato que es porque ya usa quotemeta(el módulo tiene un problema al reconocer \ o yo no he sabido como escaparlo), entonces, la solución parcial y bastante desprolija a ésto fue copiar y modificar el código del módulo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $begin = '\begin{itemize}';
  2. my $end   = '\end{itemize}';
  3. my @re;
  4.  
  5. my $qb  = quotemeta $begin;
  6. my $qe  = quotemeta $end;
  7. my $fb  = quotemeta substr $begin => 0, 1;
  8. my $fe  = quotemeta substr $end   => 0, 1;
  9.  
  10. my $tb  = quotemeta substr $begin => 1;
  11. my $te  = quotemeta substr $end   => 1;
  12.  
  13. my $add;
  14.   if ($fb eq $fe) {
  15.           push @re =>
  16.          qq /(?:$qb(?:(?>[^$fb]+)|$fb(?!$tb)(?!$te)|(?-1))*$qe)/;
  17.         }
  18.         else {
  19.           my   @clauses =  "(?>[^$fb$fe]+)";
  20.            push @clauses => "$fb(?!$tb)" if length $tb;
  21.            push @clauses => "$fe(?!$te)" if length $te;
  22.            push @clauses => "(?-1)";
  23.            push @re      =>  qq /(?:$qb(?:@clauses)*$qe)/;
  24.         }
  25. my $regex = qr /(@re)/;
  26.  
  27. $archivo =~ s/$regex/Cortar\n$1\nAqu\n/gmxs;
  28. say "$archivo";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
funciona, la expresión regular se puede reducir y extender los casos en los que deseo capturar
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $extract = qr /(?:enumerate|description|itemize) /x;
  2. my $regex = qr /
  3. (
  4.     (?:
  5.       \\begin\{$extract\}
  6.       (?:
  7.         (?>[^\\]+)|
  8.         \\
  9.         (?!begin\{$extract\})
  10.         (?!end\{$extract\})|
  11.         (?-1)
  12.       )*
  13.       \\end\{$extract\}
  14.     )
  15. )
  16. /x;
  17.  
  18. $archivo =~ s/($regex)/Cortar\n$1\nAqu\n/gmxs;
  19. say "$archivo";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

La pregunta es: ¿Se puede hacer ésto usando (DEFINED)?, he leído un poco sobre un concepto al que llaman grammars en ingles y usan (DEFINED) en varios de ellos, los ejemplos no son tan simples, pero al parecer se ajusta a lo busco en la mayoría de los casos.

Saludos
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)

Re: (?(DEFINE)...) y recursividad en expresión regular

Notapor explorer » 2016-05-18 06:58 @332

Con (DEFINE) puedes definir los distintos patrones dentro de la propia exp. reg. Incluso hasta de forma condicional, según lo que te vayas encontrando por el camino.

La explicación de (DEFINE) está en perlre, pero explica muy poco. El único ejemplo que aparece es este:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.           /(?<NAME>(?&NAME_PAT))(?<ADDR>(?&ADDRESS_PAT))
  2.            (?(DEFINE)
  3.              (?<NAME_PAT>....)
  4.              (?<ADDRESS_PAT>....)
  5.            )/x
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Ahí vemos un patrón (los primeros pares de paréntesis), seguidos por un (?(DEFINE) ... ) donde definimos los patrones que hemos usado en la línea anterior.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 6 invitados