• Publicidad

Eliminar primera y última línea de un cadena

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

Eliminar primera y última línea de un cadena

Notapor pablgonz » 2015-12-11 16:20 @722

Hola a todos nuevamente, estoy trabajando en un script y me he topado con un problema de una líneas sobrantes (la primera y la última) al extraer un bloque de texto con una expresión regular. Si el archivo de entrada es así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. \documentclass{article}
  2. \usepackage{lmodern}
  3. \usepackage{pstricks-add}
  4. \begin{document}
  5. Texto texto texto
  6. % codigo uno
  7. \begin{postscript}
  8. code uno
  9. \end{postscript}
  10. Texto texto texto
  11. Texto texto texto
  12. % codigo dos
  13. texto\begin{pspicture}(-0.5,-0.5)(5,3.5)
  14. code dos
  15. \end{pspicture}texto
  16. Texto texto texto
  17. Texto texto texto
  18. % código tres
  19. \psset{
  20. unit=1.0cm,
  21. algebraic=true,
  22. dimen=middle,
  23. linewidth=0.8pt
  24. }
  25. \begin{pspicture}(-0.5,-0.5)(5,3.5)
  26. code tres
  27. \end{pspicture}
  28. Texto texto texto
  29. % código cuatro
  30. \begin{pgfpicture}
  31. code cinco
  32. \end{pgfpicture}
  33. Texto texto texto
  34. % código cinco
  35. TIKZ
  36. \begin{tikzpicture}
  37. code cinco
  38. \end{tikzpicture}
  39. % código seis
  40. Texto texto texto
  41. \begin{forest}
  42. code seis
  43. \end{forest}
  44.  
  45. Texto texto texto
  46.  
  47. \begin{postscript}
  48. \begin{ganttchart}
  49. ganttchart
  50. \end{ganttchart}
  51. \end{postscript}
  52. final
  53. \end{document}
  54.  
  55. \begin{pspicture}(-0.5,-0.5)(5,3.5)
  56. IGNORAR
  57. \end{pspicture}
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
y pasar este script con la opción --source:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.22;
  3. use File::Basename;
  4. use Getopt::Long qw(:config bundling_override require_order);
  5. use autodie;                  
  6. use File::Temp qw(tempdir);
  7. use File::Copy;
  8. #--------------------------- Constantes -------------------------------#
  9. my $BPL       = '\begin{postscript}';
  10. my $EPL       = '\end{postscript}';
  11. my $sipgf     = 'pgfpicture';
  12. my $nopgf     = 'pgfinterruptpicture';
  13. my $BP        = '\\\\begin\{postscript\}';
  14. my $EP        = '\\\\end\{postscript\}';
  15. my $tempDir   = tempdir( CLEANUP => 1); # temporary directory
  16. #-------------------------- Getopt::Long ------------------------------#
  17. my $other     = "other";        # other environment for search
  18. my $imageDir  = "images";       # dir for images (images default)
  19. my $ignore    = "ignore";       # ignore verbatim environment
  20. my $clear     = 0;              # 1->clear all temporary files
  21. my $source    = 0;              # 1->extrae codigo de las imágenes
  22. my $nopreview = 0;              # 1->activa el modo nopreview
  23. my $subfile   = 0;              # 1->activa el modo nopreview
  24. my $latex     = 0;              # 1->create all images using latex
  25. my $xetex     = 0;              # 1->create all images using xelatex
  26. my $luatex    = 0;              # 1->create all images using lualatex
  27. my $png       = 0;              # 1->create .png using Ghoscript
  28. my $jpg       = 0;              # 1->create .jpg using Ghoscript
  29. my $eps       = 0;              # 1->create .eps using pdftops
  30. my $svg       = 0;              # 1->create .svg using pdf2svg
  31. my $ppm       = 0;              # 1->create .ppm using pdftoppm
  32. my $all       = 0;              # 1->create all images type
  33. my $miktex    = 0;              # 1->enable write 18 for miktex system
  34. my $Verbose   = 0;              # 0 or 1, logfile  
  35. #------------------------ Opciones y ayuda ----------------------------#
  36. my $usage = <<"END_OF_USAGE";
  37. Uso: script [opciones] entrada.tex [salida]
  38. END_OF_USAGE
  39.  
  40. ### error
  41. sub errorUsage { die "@_ (use script --help)\n"; }
  42.  
  43. ### Getopt::Long
  44. my $result=GetOptions (
  45.     'imgdir=s'          => \$imageDir, # images
  46.     'ignore=s'          => \$ignore, # ignore, ignore*
  47.     'other=s'           => \$other, # other, other*
  48.     'e|eps'             => \$eps, # pdftops
  49.     'j|jpg'             => \$jpg, # gs
  50.     'p|png'             => \$png, # gs
  51.     'P|ppm'             => \$ppm, # pdftoppm
  52.     's|svg'             => \$svg, # pdf2svg
  53.     'a|all'             => \$all, # all
  54.     'c|clear'           => \$clear, # clear
  55.     'h|help'            => \$::opt_help, # help
  56.     'subfile'           => \$subfile, # subfile
  57.     'source'            => \$source, # src
  58.     'np|nopreview'      => \$nopreview, #
  59.     'xetex'             => \$xetex, #
  60.     'latex'             => \$latex, #
  61.     'luatex'            => \$luatex,#
  62.     'miktex'            => \$miktex, #
  63.     'Verbose'           => \$Verbose, # verbose
  64.     ) or die "use script --help para ver las opciones\n";
  65.  
  66. ### help
  67. if ($::opt_help) {
  68.     print $usage;
  69.     exit(0);
  70. }
  71.  
  72. #--------------- Chequeamos los argumentos de entrada -----------------#
  73. @ARGV > 0 or errorUsage "Falta ingresar el nombre del archivo de entrada";
  74. @ARGV < 3 or errorUsage "Opción desconocida o varios archivos de entrada";
  75.  
  76. #--------------------- Arreglo de la extensión ------------------------#
  77. my @SuffixList = ('.tex', '', '.ltx');    # posibles
  78. my ($name, $path, $ext) = fileparse($ARGV[0], @SuffixList);
  79. $ext = '.tex' if not $ext;
  80.  
  81. ### El nombre del archivo de salida se guarda en $ARGV[1]
  82. my $output = $ARGV[1];
  83.  
  84. #---------------------- Abrimos el archivo ----------------------------#
  85. open my $ENTRADA, '<', "$name$ext";
  86. my $archivo;
  87. {
  88.     local $/;
  89.     $archivo = <$ENTRADA>;
  90. }
  91. close   $ENTRADA;
  92.  
  93. ### Creamos el directorio para las imágenes
  94. -e $imageDir or mkdir($imageDir,0744) or die "No puedo crear $imageDir: $!\n";
  95.  
  96. ### Dividimos el archivo de entrada
  97. my($cabeza,$cuerpo,$final) = $archivo =~ m/\A (.+?) (\\begin\{document\} .+?)(\\end\{document\}.*)\z/msx;
  98.  
  99. ### Verbatim environments
  100. my $VERBATIM  = qr/(?: (v|V)erbatim\*?| PSTexample | aling)/xi;
  101.  
  102. ### postscript environment
  103. my $POSTSCRIPT = qr/(?: postscript)/xi;
  104.  
  105. ### tikzpicture environment
  106. my $ENVIRONMENT    = qr/(?: tikzpicture | pspicture\*?)/xi;
  107.  
  108. #------------------ Expresiones regulares en $cuerpo ------------------#
  109.  
  110. ### \pspicture to \begin{pspicture}
  111. $cuerpo =~ s/\\pspicture(\*)?(.+?)\\endpspicture/\\begin{pspicture$1}$2\\end{pspicture$1}/gmsx;
  112.  
  113. ### tikz/pst to Postscript
  114. $cuerpo =~ s/\\begin\{$POSTSCRIPT\}.+?\\end\{$POSTSCRIPT\}(*SKIP)(*F)|
  115.         (
  116.         (?:\\(psset|tikzset)(\{(?:\{.*?\}|[^\{])*\}).*?)?  # si está lo guardo
  117.         (\\begin\{($ENVIRONMENT)\} (.*?)  \\end\{\g{-2}\})
  118.     )
  119.     /$BPL\n$1\n$EPL/gmsx;
  120.  
  121. ### pgfpicture to Postscript
  122. $cuerpo =~ s/\\begin\{$POSTSCRIPT\}.+?\\end\{$POSTSCRIPT\}(*SKIP)(*F)|
  123.     (
  124.         \\begin\{$sipgf\}
  125.             .*?
  126.             (
  127.                 \\begin\{$nopgf\}
  128.                 .+?
  129.                 \\end\{$nopgf\}
  130.                 .*?
  131.             )*?
  132.         \\end\{$sipgf\}
  133.     )
  134.     /$BPL\n$1\n$EPL/gmsx;
  135.  
  136. ### other to PostScript
  137. my $EXPORT  = qr/(forest|ganttchart|tikzcd|circuitikz|dependency|$other\*?)/x;
  138.  
  139. $cuerpo =~ s/\\begin\{$POSTSCRIPT\}.+?\\end\{$POSTSCRIPT\}(*SKIP)(*F)|
  140.         (\\begin\{($EXPORT)\} (.*?)  \\end\{\g{-2}\})
  141.         /$BPL\n$1\n$EPL/gmsx;
  142.  
  143. #----------------- Creación del fichero de imágenes -------------------#
  144. ### $nopreview mode
  145. if ($nopreview) {
  146. my @env_extract;
  147.  
  148. while ( $cuerpo =~ m/(?<=$BP)(?<env_src>.+?)(?=$EP)/gms ) { # recorremos $cuerpo
  149.     push @env_extract, $+{env_src}."\n\\newpage\n";
  150. }
  151. open my $SALIDA, '>', "$imageDir/$name-fig$ext";
  152. print $SALIDA $cabeza."\\pagestyle{empty}\n\\begin{document}\n"."@env_extract\n"."\\end{document}";
  153. close $SALIDA;
  154. } # close $nopreview
  155. ### preview mode (default)
  156. else {
  157. my $opcion = $xetex ? 'xetex,'
  158.            : $latex ? ''
  159.            :          'pdftex,'
  160.            ;
  161.  
  162. my $preview = <<"EXTRA";
  163. \\AtBeginDocument\{%
  164. \\RequirePackage\[${opcion}active,tightpage\]\{preview\}%
  165. \\renewcommand\\PreviewBbAdjust\{-60pt -60pt 60pt 60pt\}%
  166. \\newenvironment\{postscript\}\{\}\{\}%
  167. \\PreviewEnvironment\{postscript\}\}%
  168. EXTRA
  169. # write
  170. open my $SALIDA, '>', "$imageDir/$name-fig$ext";
  171. print   $SALIDA $preview.$cabeza.$cuerpo."\\end{document}";
  172. close   $SALIDA;
  173. } # close preview
  174.  
  175. #-------------------- Extracción de ficheros fuente -------------------#
  176. if ($source) {
  177. my $src_file = "$name-src-";   # nombre del archivo de salida
  178. my $srcNo    = 1; # contador para los ficheros fuente
  179.  
  180. while ($cuerpo =~ m/(?<=$BP)(?<env_src>.+?)(?=$EP)/gms) { # recorremos $cuerpo
  181.  
  182. open my $SALIDA, '>', "$imageDir/$src_file$srcNo$ext";
  183.     print $SALIDA $+{env_src};
  184. close $SALIDA;
  185.     }
  186. continue {
  187.     $srcNo++; # auto incremento del contador
  188. }
  189. } # close $source
  190.  
  191. #-------------------- Extracción de subficheros -----------------------#
  192. if ($subfile) {
  193. my $sub_file = "$name-fig-";   # nombre del archivo de salida
  194. my $subNo = 1; # subfile number
  195.  
  196. while ($cuerpo =~ m/(?<=$BP)(?<env_src>.+?)(?=$EP)/gms) { # recorremos $cuerpo
  197.  
  198. open my $SALIDA, '>', "$imageDir/$sub_file$subNo$ext";
  199. print $SALIDA <<"EOC";
  200. $cabeza\\pagestyle\{empty\}\n\\begin\{document\}$+{'env_src'}\\end\{document\}
  201. EOC
  202. close $SALIDA;
  203.     } # close while
  204. continue {
  205.     $subNo++; # auto incremento del contador
  206. }
  207. } # close $subfile
  208.  
  209. #------------------ Creación del archivo de salida --------------------#
  210. if (defined $output) {
  211. if ($output =~ /(^\-|^\.).*?/){ # No comienze por -, -- o .
  212.     die "$output no es un nombre valido para el archivo de salida\n";
  213.     }
  214. if ($output eq "$ARGV[0]" or $output eq "$name") { # $output = $input
  215.     $output = "$name-out$ext";  
  216.     }
  217. if ($output =~ /.*?$ext/){ # Si $output termina en .ltx o .tex la quitamos
  218.     $output =~ s/(.+?)$ext/$1/gms;
  219.     }
  220.  
  221. ### Convertimos Postscript a includegraphics
  222. my $grap="\\includegraphics[scale=1]{$name-fig-";
  223. my $close = '}';
  224. my $imgNo = 1; # contador para las imágenes
  225.  
  226. $cuerpo =~ s/$BP.+?$EP/$grap@{[$imgNo++]}$close/msg; # cambiamos
  227.  
  228. # print "Creamos $output$ext\n" if $verbose;
  229. open my $SALIDA, '>', "$tempDir/$output$ext";
  230.     print $SALIDA <<"EOC";
  231. $cabeza$cuerpo$final
  232. EOC
  233. close $SALIDA;
  234. copy "$tempDir/$output$ext", "$tempDir/mojo";
  235. } # cerramos defined
  236.  
  237. move "$tempDir/$output$ext", "$output$ext";
  238. __END__
  239.  
Coloreado en 0.008 segundos, usando GeSHi 1.0.8.4
crea los archivos, pero, deja una línea en blanco al principio y al final de cada archivo generado, por ejemplo, crea
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1.  
  2. code uno
  3.  
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
y debería crear
Sintáxis: [ Descargar ] [ Ocultar ]
Using latex Syntax Highlighting
  1. code uno
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
. He usado las aserciones de inspección (?<=$BP) y (?=$EP) para extraer lo que deseo en esta opción y en otra ($subfile) en la cual funciona correctamente. Si no he entendido mal cómo funcionan, estas no incluyen $BP ni $EP en la captura pero al parecer las cambia por una línea en blanco.
Saludos
Pablo
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)

Publicidad

Re: Eliminar primera y última línea de un cadena

Notapor explorer » 2015-12-11 17:40 @777

while ($cuerpo =~ m/(?<=$BP)(?<env_src>.+?)(?=$EP)/gms) {

No es necesario usar aserciones de ancho cero, en este caso. Estás aplicando un patrón a $cuerpo, para buscar el interior entre dos marcas, y esa captura la haces con paréntesis (y con nombre), así que no es necesario el uso de patrones en aserciones de ancho cero, ya que no son capturados. Sí que son más útiles en las sustituciones (porque no queremos sustituir esos patrones).

Quedaría así:

while ($cuerpo =~ m/$BP(?<env_src>.+?)$EP/gms) {

En cuanto a lo de que aparecen líneas en blanco, indudablemente es que esos caracteres no son capturados por $BP o $EP. Ejemplo, si tenemos

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2.  
  3. my $BP =         quotemeta('\begin{postscript}');
  4. my $EP =         quotemeta('\end{postscript}'  );
  5.  
  6. my $cuerpo = '\begin{postscript}
  7. code uno
  8. \end{postscript}
  9.  
  10. \begin{postscript}
  11. code dos
  12. \end{postscript}
  13. ';
  14.  
  15. while ($cuerpo =~ m/$BP(?<env_src>.+?)$EP/gms) {
  16.  
  17.     print "[$+{env_src}]";
  18. }
  19.  
  20. print "\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
La salida es:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
[
code uno
][
code dos
]
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
que es justo lo que te pasa. Si agregamos a los patrones el que capturen los posibles caracteres espacio,
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2.  
  3. my $BP =         quotemeta('\begin{postscript}') . '\s*';
  4. my $EP = '\s*' . quotemeta('\end{postscript}'  );
  5.  
  6. my $cuerpo = '\begin{postscript}
  7. code uno
  8. \end{postscript}
  9.  
  10. \begin{postscript}
  11. code dos
  12. \end{postscript}
  13. ';
  14.  
  15. while ($cuerpo =~ m/$BP(?<env_src>.+?)$EP/gms) {
  16.  
  17.     print "[$+{env_src}]";
  18. }
  19.  
  20. print "\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
la salida ya cambia:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
[code uno][code dos]
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Humm... casi mejor poner los '\s*' en el patrón principal:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. while ($cuerpo =~ m/$BP\s*(?<env_src>.+?)\s*$EP/gms) {
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: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Eliminar primera y última línea de un cadena

Notapor pablgonz » 2015-12-11 18:50 @826

Genial, no pude dar con esa línea, usé las aserciones pensando que era lo indicado en este caso, leeré más respecto de estas.

Un par de consultas respecto a la respuesta que me has dado:
1. Al ver el código que dejas de ejemplo veo que usas quotemeta(...), es decir, que estas "escapando" el contenido dentro de (...), entonces si cambio de:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $BPL       = '\begin{postscript}';
  2. my $EPL       = '\end{postscript}';
  3. my $BP        = '\\\\begin\{postscript\}';
  4. my $EP        = '\\\\end\{postscript\}';
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
a
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $BP =         quotemeta('\begin{postscript}');
  2. my $EP =         quotemeta('\end{postscript}'  );
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
¿funcionará en todos los casos?

2. ¿Es mejor usar paréntesis de captura con nombre o seguir usando la referencia $1, $2, etc.?

3. Uso varias veces (*SKIP)(*F)| regex, en el lado derecho, ¿puedo volver a usar (*SKIP)?, no lo he intentado, pero lo de (*SKIP)(*F) es una de las cosas más geniales de Perl (algunos amigos han intentado hacer cosas parecidas en otros lenguajes y al parecer no se puede en todos).

4. Siempre escribes los códigos con un formato bonito de espacios y tabulaciones. ¿Qué opciones usas en perltidy? ¿o solo lo haces manualmente?

Agradecido:
Pablo.

P.D.: Ahora sí cambie la línea del shebang y ocupo Getopt de manera más eficiente.
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)

Re: Eliminar primera y última línea de un cadena

Notapor explorer » 2015-12-13 08:33 @398

pablgonz escribiste:1. Al ver el código que dejas de ejemplo veo que usas quotemeta(...), es decir, que estas "escapando" el contenido dentro de (...), entonces si cambio de:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $BPL       = '\begin{postscript}';
  2. my $EPL       = '\end{postscript}';
  3. my $BP        = '\\\\begin\{postscript\}';
  4. my $EP        = '\\\\end\{postscript\}';
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
a
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $BP =         quotemeta('\begin{postscript}');
  2. my $EP =         quotemeta('\end{postscript}'  );
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
¿funcionará en todos los casos?
Cuestión de probar :)

Si, en informática, estamos repitiendo algo muchas veces (en tu caso, escapar caracteres con '\'), es que algo no estamos haciendo bien.

Sabiendo que Perl sabe "escapar" caracteres, bien sea usando quotemeta() o "\Q...\E", pues buena gana de hacerlo nosotros.

pablgonz escribiste:2. ¿Es mejor usar paréntesis de captura con nombre o seguir usando la referencia $1, $2, etc.?
Da igual. Bueno, no. Es más claro con nombre, además de ser más robusto (resistirá los futuros cambios que hagamos, si hacemos alguna). Hay que escribir más, pero el código queda más claro.

pablgonz escribiste:3. Uso varias veces (*SKIP)(*F)| regex. En el lado derecho ¿puedo volver a usar (*SKIP)? No lo he intentado, pero lo de (*SKIP)(*F) es una de las cosas más geniales de Perl (algunos amigos han intentado hacer cosas parecidas en otros lenguajes y al parecer no se puede en todos).
Yo creo que sí se puede usar en otros lenguajes, siempre y cuando hagan uso de la biblioteca PCRE.

Lo de usarlo en el lado derecho... pues habría que verlo, pero antes hay que entender qué es lo que hace.

El (*SKIP) dice que si se cumple el patrón anterior a él, las siguientes pruebas de búsqueda deben realizarse a partir de ese punto, y no volver hacia atrás. Y el (*FAIL) marca la búsqueda como fallida, por lo que reinicia la búsqueda.

Como estos patrones especiales los tienes en el lado izquierdo de un patrón de alternancia '|', entonces se ejecutan antes que el patrón que está en el lado derecho. Si pones otro (*SKIP)(*FAIL) en el lado derecho, tendrá el mismo comportamiento: si encuentra el patrón, seguirá buscando desde ese punto. Y como hay un (*FAIL), nunca se cumplirá la exp. reg., por lo que no habrá sustitución (salvo que agregues un tercer caso con '|').

pablgonz escribiste:4. Siempre escribes los códigos con un formato bonito de espacios y tabulaciones. ¿Qué opciones usas en perltidy? ¿o solo lo haces manualmente?
perltidy hace bastante, pero no distingue todos los casos. El orden que hago es: primero perltidy y luego ajuste manual (no se puede aplicar perltidy otra vez porque desbarata todo el formateo manual).

Las reglas de formateo las saqué del libro PBP. Las primeras reglas te enseñan a escribir código de esa manera.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
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 8 invitados