• Publicidad

Expresión regular para texto anidado

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

Expresión regular para texto anidado

Notapor pablgonz » 2014-12-16 00:32 @064

Vuelvo al foro con una duda (para variar) con una expresión regular para modificar texto anidado. Un ejemplo para que se entienda la idea, si el archivo de entrada es así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. \documentclass{article}
  2. % Las líneas que están en
  3. % éste sector no deben modificarse
  4. \begin{document}
  5.  
  6. Texto texto texto
  7.  
  8. \begin{pgfpicture}
  9. \pgfpathmoveto{\pgfpoint{0cm}{0cm}} %
  10. \newbox\mybox
  11. \setbox\mybox=\hbox{
  12. \begin{pgfinterruptpicture}
  13. anidado\begin{pgfpicture} % subpicture
  14. \pgfpathmoveto{\pgfpoint{1cm}{0cm}}
  15. \pgfpathlineto{\pgfpoint{1cm}{1cm}}
  16. \pgfusepath{stroke}
  17. \end{pgfpicture} termina el anidado
  18. \end{pgfinterruptpicture}
  19. }
  20. \pgfqbox{\mybox}%
  21. \pgfpathlineto{\pgfpoint{0cm}{1cm}}
  22. \pgfusepath{stroke}
  23. \end{pgfpicture}
  24.  
  25. texto texto
  26. \begin{pgfpicture}
  27. \begin{pgfscope}
  28. {
  29. \pgfsetarrows{-to}
  30. \pgfpathmoveto{\pgfpointorigin}\pgfpathlineto{\pgfpoint{2ex}{2ex}}
  31. \pgfusepath{stroke}
  32. }
  33. \pgfpathmoveto{\pgfpoint{3ex}{0ex}}\pgfpathlineto{\pgfpoint{5ex}{2ex}}
  34. \pgfusepath{stroke}
  35. \end{pgfscope}
  36. \pgfpathmoveto{\pgfpoint{6ex}{0ex}}\pgfpathlineto{\pgfpoint{8ex}{2ex}}
  37. \pgfusepath{stroke}
  38. \end{pgfpicture}
  39. \end{document}
  40. % Lo que está acá al final tampoco debe modificarse
  41. %\endpspicture o \end{pspicture} \end{document} no debería cambiar
  42.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
me gustaría dejarlo de esta manera:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. \documentclass{article}
  2. % Las líneas que están en
  3. % éste sector no deben modificarse
  4. \begin{document}
  5.  
  6. Texto texto texto
  7.  
  8. \begin{postscript}
  9. \begin{pgfpicture}
  10. \pgfpathmoveto{\pgfpoint{0cm}{0cm}} %
  11. \newbox\mybox
  12. \setbox\mybox=\hbox{
  13. \begin{pgfinterruptpicture}
  14. anidado\begin{pgfpicture} % subpicture
  15. \pgfpathmoveto{\pgfpoint{1cm}{0cm}}
  16. \pgfpathlineto{\pgfpoint{1cm}{1cm}}
  17. \pgfusepath{stroke}
  18. \end{pgfpicture} termina el anidado
  19. \end{pgfinterruptpicture}
  20. }
  21. \pgfqbox{\mybox}%
  22. \pgfpathlineto{\pgfpoint{0cm}{1cm}}
  23. \pgfusepath{stroke}
  24. \end{pgfpicture}
  25. \end{postscript}
  26.  
  27. texto texto
  28. \begin{postscript}
  29. \begin{pgfpicture}
  30. \begin{pgfscope}
  31. {
  32. \pgfsetarrows{-to}
  33. \pgfpathmoveto{\pgfpointorigin}\pgfpathlineto{\pgfpoint{2ex}{2ex}}
  34. \pgfusepath{stroke}
  35. }
  36. \pgfpathmoveto{\pgfpoint{3ex}{0ex}}\pgfpathlineto{\pgfpoint{5ex}{2ex}}
  37. \pgfusepath{stroke}
  38. \end{pgfscope}
  39. \pgfpathmoveto{\pgfpoint{6ex}{0ex}}\pgfpathlineto{\pgfpoint{8ex}{2ex}}
  40. \pgfusepath{stroke}
  41. \end{pgfpicture}
  42. \begin{postscript}
  43. \end{document}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Utilizo el siguiente script:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.18;
  3. use strict;                     # Somos estrictos
  4. use autodie;                    # muere si ocurre un error
  5. use File::Basename;             # separa el archivo de entrada
  6. use File::Path;                 # Para crear y remover directorios
  7. #--------------------- Arreglo de la extensión -------------------------
  8. my @SuffixList = ('.tex', '', '.ltx');               # posible extensión
  9. my ($name, $path, $ext) = fileparse($ARGV[0], @SuffixList);
  10. $ext = '.tex' if not $ext;
  11.  
  12. #------------------- Abrimos el archivo -------------------------------
  13. open my $ENTRADA, '<', "$name$ext";
  14. my $archivo;
  15. {
  16.     local $/;
  17.     $archivo = <$ENTRADA>;
  18. }
  19. close   $ENTRADA;
  20.  
  21. #--------------------- Dividimos el archivo de entrada -----------------
  22. # ?= no guarda en $ , capturamos solo lo que nos interesa
  23. my($cabeza,$cuerpo) = $archivo =~ m/(.+(?=^\\begin{document})) (.+(?=^\\end{document}.*))/msx;
  24.  
  25. #----------------- Buscamos entornos anidados en pgfpicture
  26. my $pgf = '{pgfpicture}';       #
  27. my $nopgf = '{pgfinterruptpicture}';    #
  28.  
  29. $cuerpo =~ s/(\\begin$pgf([^\\begin$nopgf .+ \\end$nopgf])?.+\\end$pgf)/\\begin{postscript}\n$1\n\\end{postscript}/gms;
  30.  
  31. open my $SALIDA, '>', "$name-out$ext";
  32.     print $SALIDA "$cabeza$cuerpo\\end\{document\}";
  33. close $SALIDA;
  34.  
  35. __END__
  36.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

Es decir, deseo dejar todo lo que esté entre
Sintáxis: [ Descargar ] [ Ocultar ]
  1. \begin{pgfpicture} ... \end{pgfpicture} 

dentro de
Sintáxis: [ Descargar ] [ Ocultar ]
  1. \begin{postscript} ... \end{postscript} 

El problema es que pgfpicture puede, o no, aparecer "anidado" entre de las palabras
Sintáxis: [ Descargar ] [ Ocultar ]
  1. \begin{pgfinterruptpicture} ... \end{pgfinterruptpicture} 
incluso más de una vez, un caso extremo:
Sintáxis: [ Descargar ] [ Ocultar ]
  1. \begin{pgfpicture} 
  2. Algo  
  3. \begin{pgfinterruptpicture} 
  4. algo quizas 
  5. \begin{pgfpicture}  
  6. algo quizas 
  7. \end{pgfpicture}  
  8. algo quizas 
  9. \end{pgfinterruptpicture} 
  10. algo quizas 
  11. \begin{pgfinterruptpicture} 
  12. algo quizas 
  13. \begin{pgfpicture}  
  14. algo quizas 
  15. \end{pgfpicture}  
  16. algo quizas 
  17. \end{pgfinterruptpicture} 
  18. algo quizas 
  19. \end{pgfpicture} 

Miré varios ejemplos de cómo extraer texto entrecomillado y mi problema es parecido, pero, no doy con la expresión regular correcta para hacer los cambios.

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

Publicidad

Re: Expresión regular para texto anidado

Notapor explorer » 2014-12-16 14:24 @641

Es algo complicado, desde luego.

Esta es una solución, pero no sé si funcionará en todos los casos. Al menos, funciona con el ejemplo propuesto.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.18;
  3. use autodie;                    # muere si ocurre un error
  4. use File::Basename;             # separa el archivo de entrada
  5. use File::Slurp;
  6.  
  7. #--------------------- Arreglo de la extensión -------------------------
  8. my @SuffixList = ('.tex', '', '.ltx');               # posible extensión
  9. my ($name, $path, $ext) = fileparse($ARGV[0], @SuffixList);
  10. $ext = '.tex' if not $ext;
  11.  
  12. #------------------- Abrimos el archivo -------------------------------
  13. my $archivo = read_file("$name$ext");
  14.  
  15. #--------------------- Dividimos el archivo de entrada ----------------
  16. my($cabeza,$cuerpo) = $archivo =~ m/\A (.*) ( ^ \\begin{document} .+ ^ \\end{document} .* \z)/msx;
  17.  
  18. #----------------- Buscamos entornos anidados en pgfpicture -----------
  19. my $sipgf = 'pgfpicture';
  20. my $nopgf = 'pgfinterruptpicture';
  21.  
  22. $cuerpo =~ s/
  23.     (
  24.         \\begin{$sipgf}
  25.             .*?
  26.             (?:
  27.                 \\begin{$nopgf}
  28.                 .+?
  29.                 \\end{$nopgf}
  30.                 .*?
  31.             )*?
  32.         \\end{$sipgf}
  33.     )
  34.     /\\begin{postscript}\n$1\n\\end{postscript}/gmsx;
  35.  
  36. #----------------- Salida ---------------------------------------------
  37. write_file("$name-out$ext", "$cabeza$cuerpo");
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Expresión regular para texto anidado

Notapor pablgonz » 2014-12-17 07:05 @336

Muchas gracias, esa era la expresión regular que estaba buscando, el archivo de entrada no es más complejo que el mostrado en el ejemplo.

Siguiendo con el tema del anidado, que no es para nada fácil, usando el mismo script me gustaría modificar el texto delimitado por \begin{postscript} ... \end{postscript} dentro de $cuerpo, el tema es que aveces aparece anidado dentro de sí mismo. Por ejemplo, si la entrada es de esta forma:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. texto\begin{postscript}
  2. texto texto texto
  3. \begin{postscript}
  4.  
  5. code code code
  6.  
  7. \end{postscript}
  8. \end{postscript}
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

me gustaría dejarlo de la siguiente forma:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. texto\begin{postscript}
  2. texto texto texto
  3.  
  4. code code code
  5.  
  6. \end{postscript}
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Es decir, deseo capturar lo que esté entre \begin{postscript} ... \end{postscript} sin capturar \begin{postscript} ... \end{postscript} entre ellos. Sé que siempre aparecen emparejados y sólo se puede dar un anidado, como:
Sintáxis: [ Descargar ] [ Ocultar ]
  1. \begin{postscript} 
  2. Quizás algo quizás no 
  3. \begin{postscript} 
  4. code code code 
  5. \end{postscript} 
  6. Quizás algo quizás no 
  7. \end{postscript} 

He jugado un poco y tengo esta expresión regular:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $cuerpo =~ s/
  2.     (\\begin{postscript}.*?)  # inicio
  3.             (?:\\begin{postscript}\s) # no lo deseo
  4.              (.*?) # lo deseo
  5.             (?:\\end{postscript}\s)  # no lo deseo
  6.      (.*?\\end{postscript} )  # final
  7.      /$1$2$3/gmsx;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

la cual funciona (creo que se puede optimizar un poco), pero, al agregar esta expresión regular antes:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $other = "other";    # otro entorno
  2. $cuerpo =~ s/(\\begin\{$other(\*)?\}(.+?)\\end\{$other(\*)?\})/\\begin{postscript}\n$1\n\\end{postscript}/gms;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

deja de funcionar de manera correcta. Creo que el * opcional me está dando el problema.

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

Re: Expresión regular para texto anidado

Notapor explorer » 2014-12-17 13:47 @616

Eso lo puedes saber si sacas el $cuerpo modificado, para ver qué cambios ha sufrido.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Expresión regular para texto anidado

Notapor pablgonz » 2014-12-17 14:15 @636

Ok, revisé el archivo generado y cambié el código a:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.16;
  3. use strict;                                                     # Somos estrictos
  4. use autodie;                                            # muere si ocurre un error
  5. use File::Basename;                                     # separa el archivo de entrada
  6. use File::Path;                     # Para crear y remover directorios
  7. #------------------------ Constantes -----------------------------------
  8. my $imageDir = 'images/';                               # directorio de imágenes
  9. my $other = "other";                            # directorio de imágenes
  10. #--------------------- Arreglo de la extensión -------------------------
  11. my @SuffixList = ('.tex', '', '.ltx');               # posible extensión
  12. my ($name, $path, $ext) = fileparse($ARGV[0], @SuffixList);
  13. $ext = '.tex' if not $ext;
  14.  
  15. #---------------- Creamos el directorio para las imágenes --------------
  16. -e $imageDir or mkdir($imageDir,0744) or die "No puedo crear $imageDir: $!\n";
  17.  
  18. #------------------- Abrimos el archivo -------------------------------
  19. open my $ENTRADA, '<', "$name$ext";
  20. my $archivo;
  21. {
  22.     local $/;
  23.     $archivo = <$ENTRADA>;
  24. }
  25. close   $ENTRADA;
  26.  
  27. #--------------------- Dividimos el archivo de entrada -----------------
  28. my($cabeza,$cuerpo,$final) = $archivo =~ m/\A (.+? ^\\begin{document}) (.+) (^ \\end{document} .*) \z/msx;
  29.  
  30. $cuerpo =~ s/\\pspicture(\*)?(.+?)\\endpspicture/\\begin{pspicture$1}$2\\end{pspicture$1}/gms;
  31.  
  32. #$cuerpo =~ s/(\\begin\{$other\}(.+?)\\end\{$other\})/\\begin{postscript}\n$1\n\\end{postscript}/gms;
  33. $cuerpo =~ s/(\\begin\{$other(\*)?\}(.+?)\\end\{$other(\*)?\})/\\begin{postscript}\n$1\n\\end{postscript}/gms;
  34.  
  35. my $sipgf = 'pgfpicture';
  36. my $nopgf = 'pgfinterruptpicture';
  37.  
  38. $cuerpo =~ s/
  39.     (
  40.         \\begin{$sipgf}
  41.             .*?
  42.             (?:
  43.                 \\begin{$nopgf}
  44.                 .+?
  45.                 \\end{$nopgf}
  46.                 .*?
  47.             )*?
  48.         \\end{$sipgf}
  49.     )
  50.     /\\begin{postscript}\n$1\n\\end{postscript}/gmsx;
  51.    
  52. $cuerpo =~ s/
  53.         (\\begin{postscript}.*?)  # inicio
  54.             (?:\\begin{postscript}\s) # no lo deseo
  55.              (.*?) # lo deseo
  56.             (?:\\end{postscript}\s)  # no lo deseo
  57.      (.*?\\end{postscript} )\z  # final
  58.      /$1$2$3/gmsx;
  59.  
  60. open my $SALIDA, '>', "$name-out$ext";
  61.     print $SALIDA <<"EOC";
  62. $cabeza$cuerpo$final
  63. EOC
  64. close $SALIDA;
  65.  
  66. __END__
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Si el archivo de entrada es:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. \documentclass{article}
  2. % Las líneas que están en
  3. % éste sector no deben modificarse
  4. \begin{document}
  5. Entorno con other*
  6. con texto\begin{other*}(5,5)(2,2)
  7.   \pscustom[fillcolor=red!20, fillstyle=solid]{%
  8.     \pscspline(0,3)(4,2)(5,0)
  9.     \lineto(0,0)
  10.     \closepath}
  11. \end{other*}
  12.  
  13. Entorno postcript con other (sin*)
  14. \begin{postscript}
  15. Texto arriba
  16. con espacio \begin{other}(5,5)(2,2)
  17.   \pscustom[fillcolor=red!20, fillstyle=solid]{%
  18.     \pscspline(0,3)(4,2)(5,0)
  19.     \lineto(0,0)
  20.     \closepath}
  21. \end{other}
  22. \end{postscript}
  23.  
  24. Entorno postcript con other*
  25. \begin{postscript}
  26. Texto arriba
  27. \begin{other*}(5,5)(2,2)
  28.   \pscustom[fillcolor=red!20, fillstyle=solid]{%
  29.     \pscspline(0,3)(4,2)(5,0)
  30.     \lineto(0,0)
  31.     \closepath}
  32. \end{other*}
  33. Texto abajo
  34. \end{postscript}
  35. \end{document}
  36. % Hacer nada
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Se obtiene:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. \documentclass{article}
  2. % Las líneas que están en
  3. % éste sector no deben modificarse
  4. \begin{document}
  5. Entorno con other*
  6. con texto\begin{postscript}
  7. \begin{other*}(5,5)(2,2)
  8.   \pscustom[fillcolor=red!20, fillstyle=solid]{%
  9.     \pscspline(0,3)(4,2)(5,0)
  10.     \lineto(0,0)
  11.     \closepath}
  12. \end{other*}
  13. \end{postscript}
  14.  
  15. Entorno postcript con other (sin*)
  16. \begin{postscript}
  17. Texto arriba
  18. con espacio \begin{postscript}
  19. \begin{other}(5,5)(2,2)
  20.   \pscustom[fillcolor=red!20, fillstyle=solid]{%
  21.     \pscspline(0,3)(4,2)(5,0)
  22.     \lineto(0,0)
  23.     \closepath}
  24. \end{other}
  25. \end{postscript}
  26. \end{postscript}
  27.  
  28. Entorno postcript con other*
  29. \begin{postscript}
  30. Texto arriba
  31. \begin{postscript}
  32. \begin{other*}(5,5)(2,2)
  33.   \pscustom[fillcolor=red!20, fillstyle=solid]{%
  34.     \pscspline(0,3)(4,2)(5,0)
  35.     \lineto(0,0)
  36.     \closepath}
  37. \end{other*}
  38. \end{postscript}
  39. Texto abajo
  40. \end{postscript}
  41. \end{document}
  42. % Hacer nada
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
y deseo obtener ésto:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. \documentclass{article}
  2. % Las líneas que estan en
  3. % éste sector no deben modificarse
  4. \begin{document}
  5. Entorno con other*
  6. con texto\begin{postscript}
  7. \begin{other*}(5,5)(2,2)
  8.   \pscustom[fillcolor=red!20, fillstyle=solid]{%
  9.     \pscspline(0,3)(4,2)(5,0)
  10.     \lineto(0,0)
  11.     \closepath}
  12. \end{other*}
  13. \end{postscript}
  14.  
  15. Entorno postcript con other (sin*)
  16. \begin{postscript}
  17. Texto arriba
  18. con espacio
  19. \begin{other}(5,5)(2,2)
  20.   \pscustom[fillcolor=red!20, fillstyle=solid]{%
  21.     \pscspline(0,3)(4,2)(5,0)
  22.     \lineto(0,0)
  23.     \closepath}
  24. \end{other}
  25. \end{postscript}
  26.  
  27. Entorno postcript con other*
  28. \begin{postscript}
  29. Texto arriba
  30. \begin{other*}(5,5)(2,2)
  31.   \pscustom[fillcolor=red!20, fillstyle=solid]{%
  32.     \pscspline(0,3)(4,2)(5,0)
  33.     \lineto(0,0)
  34.     \closepath}
  35. \end{other*}
  36. Texto abajo
  37. \end{postscript}
  38. \end{document}
  39. % Hacer nada
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Y aquí es donde me pierdo, no sé qué debo modificar en las expresiones regulares para que el script funcione de manera correcta.

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

Re: Expresión regular para texto anidado

Notapor explorer » 2014-12-17 20:13 @884

El asunto es muy complicado, porque estamos hablando de quitar marcas que están anidadas, lo cual es, de siempre, un problema muy complicado.

Pero... estamos en Perl :)

Las expresiones regulares de Perl son las mejores de todos los lenguajes, y tienen incorporadas muchas características que ayudan en estos casos extremos, haciendo que las cosas "difíciles" sean "posibles".

La expresión que funciona (al menos a mí me ha funcionado) es:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $BP = '\\\\begin{postscript}';
  2. my $EP = '\\\\end{postscript}';
  3.  
  4. $cuerpo =~ s/
  5.  
  6.         $BP                             # marca que buscamos
  7.         .*?                             # seguido de lo que sea
  8.         (?(?=$EP)(*SKIP))               # PERO si encontramos una marca de final, terminamos
  9.         \K                              # vale, si encontramos lo anterior, nos olvidamos de ello
  10.         $BP\n                           # quitar
  11.         (.*?)                           # mantener
  12.         $EP\n                           # quitar
  13.  
  14.      /$1/gmsx;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Primero define las variables $BP y $EP, para hacer el patrón más corto y entendible.

Luego está el patrón. El truco está en el uso de una condición: si lo que sigue a '\begin{postscript}' es un '\end{postscript}', entonces se ejecuta el subpatrón especial (*SKIP).

Ese subpatrón hace que se corte el análisis o búsqueda justo en ese punto, y le pide reanudar la búsqueda, pero saltando toda la cadena no coincidente. De esa manera, estamos saltando todas las partes '\begin...' '\end...' que no contienen marcas anidadas.

Lo que sigue es lo normal: con \K le decimos que olvide todo lo encontrado hasta ahora (como si empezáramos el patrón de nuevo), y luego siguen las marcas que buscamos.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Expresión regular para texto anidado

Notapor pablgonz » 2014-12-18 20:42 @904

Genial, ahora sale como lo deseo... había leído sobre (*SKIP) pero, nunca lo había visto en acción. Concuerdo absolutamente con tus comentarios... si de expresiones regulares se trata... Perl es el mejor. Le pasé este mismo problema a un amigo, lo intentó resolver en otro lenguaje y sucedió lo lógico: luego de un par de horas me dijo que era demasiado difícil. En fin, comprendo la explicación del código que publicaste.

Solo una consulta respecto de:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $BP = '\\\\begin{postscript}';
  2. my $EP = '\\\\end{postscript}';
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

No entiendo el uso de \\\\ (lo he visto en Java alguna vez), pero, ¿por qué en éste caso?

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

Re: Expresión regular para texto anidado

Notapor explorer » 2014-12-18 22:20 @972

Lo que se pone entre comillas simples es "literal", pero hay excepciones. Una de ellas es querer poner una comilla simple. En ese caso necesitamos "escaparla": "\'".

Otra opción es la barra diagonal inversa. En situaciones normales, no es necesario "escaparla", así que podríamos haber escrito tranquilamente:

'\begin{postscript}'

y eso es lo que realmente estaríamos guardando en la variable.

Pero... resulta que la variable va a ser interpolada dentro del patrón, así que el motor de expresiones regulares se encontrará con un '\b', que traducirá a... el carácter 'backspace' (retroceso). Y no es eso lo que queremos.

Necesitamos "escapar" la barra diagonal dentro del patrón. Y eso sabemos que lo podemos hacer con otra barra diagonal: '\\b'.

Entonces, viene la pregunta, ¿cómo almacenamos una doble barra diagonal inversa en una variable? Si ponemos '\\begin{postscript}', ocurre la segunda posible excepción que puede ocurrir dentro de un entrecomillado simple: que la barra diagonal inversa se escape a sí misma.

Eso quiere decir que estas dos líneas hacen exactamente lo mismo:

$BP = '\begin{postscript}';
$BP = '\\begin{postscript}'; # ¡Oops! La barra es escapada


Bueno, pues entonces necesitamos "escapar" a las barras diagonales inversas, que están "escapando" a la verdadera barra diagonal inversa:

$BP = '\\\\begin{postscript}';

Con esa línea estamos guardando '\\begin{postscript}' dentro de la variable, y eso es lo que la exp. reg. verá. Al hacer la interpolación, quedará reducido a '\begin{postscript}'


Esto se suele hacer algunas veces en el shell...

Hay otra forma de hacerlo, que puede ser mucho más clara, usando la función quotemeta() (ver perldoc -f quotemeta):
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $BP = quotemeta '\begin{postscript}';                # guarda '\\begin\{postscript\}'
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

que, como ves, te puede ser muy útil (fíjate que ha escapado tanto la barra diagonal inversa como las llaves).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Expresión regular para texto anidado

Notapor pablgonz » 2014-12-18 23:22 @015

Ahora me queda claro, usar quotemeta deja el código más legible.

Una última pregunta: cuando divides el archivo de entrada con:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my($cabeza,$cuerpo) = $archivo =~ m/\A (.*) ( ^ \\begin{document} .+ ^ \\end{document} .* \z)/msx;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
en $cabeza guardo todo lo que esté hasta que encuentra \begin{document} sin incluirlo y en $cuerpo guardo desde \begin{document} hasta que encuentra \end{document} y lo que sigue de éste, pero, me surgió un problema que no había analizado en primera instancia.

\end{document} es para Latex el equivalente de ___END___ para Perl, es decir, debería dividir el archivo en dos partes, tal que $cabeza incluya hasta el primer \begin{document} y $cuerpo desde \begin{document} hasta la primera aparición de \end{document}, puesto que todo lo que esté después de este primer \end{document} no me interesa procesarlo.

He intentado usar:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my($cabeza,$cuerpo) = $archivo =~ m/\A (.*) ^(\\begin{document}.*?)\\end{document}/msx;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
pero, no sé si será la mejor manera de dividir el archivo.

Saludos y muchas gracias por las explicaciones.
Pablo
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)

Re: Expresión regular para texto anidado

Notapor explorer » 2014-12-19 11:06 @504

Es mejor lo que tenías en la línea 28 del código:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my($cabeza,$cuerpo,$final) = $archivo =~ m/\A (.+?) (^ \\begin{document} .+) (^ \\end{document} .*) \z/msx;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

De esa manera ya tienes las tres partes posibles. Modificas $cuerpo, y terminas con el clásico
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. print $SALIDA "$cabeza$cuerpo$final";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Siguiente

Volver a Básico

¿Quién está conectado?

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