Hace días que estoy tratando de resolver un problema con el uso de .. y un reemplazo usando hash. Trataré de explicarme de la manera más clara posible.
Intento modificar algunas palabras dentro un archivo LaTeX para extraerlas con una expresión regular, para que todo quede en forma y no extraiga contenido donde no debo, hago algunos cambios dentro de algunos entornos (verbatim y verbatim write). Los entornos donde deseo hacer los cambios siempre están emparejados (aunque estén anidados), es decir inician \begin{entorno} y terminan \end{entorno}. Los nombres de estos entornos los tengo guardados en un par de array, si está todo ordenado funciona bien, pero si se cruzan las palabras mi truco falla.
Para ser más preciso, este es mi código de ejemplo:
Using perl Syntax Highlighting
- #!/usr/bin/env perl
- use v5.26;
- use Data::Dumper;
- ### Entornos reservados
- my @reservados = qw (preview nopreview);
- ### Entornos que deseo extraer por defecto
- my @extr_tmp = qw ( pspicture psgraph PSTexample);
- ### Otros entornos que deseo extraer (pasado como argumento)
- my @otros = qw ( Otro );
- push (@extr_tmp,@otros,@reservados); # los junto todos
- my $entornos = join "|", map quotemeta, sort { length $a <=> length $b } @extr_tmp;
- $entornos = qr/$entornos/x;
- my $extraer = qr /
- (
- (?:
- \\begin\{$entornos\*?\}
- (?:
- (?>[^\\]+)|
- \\
- (?!begin\{$entornos\*?\})
- (?!end\{$entornos\*?\})|
- (?-1)
- )*
- \\end\{$entornos\*?\}
- )
- )
- /x;
- ### Entornos verbatim que conozco
- my @verb_tmp = qw (verbatim Verbatim BVerbatim SaveVerbatim PSTcode);
- my $verbatim = join "|", map quotemeta, sort { length $a <=> length $b } @verb_tmp;
- $verbatim = qr/$verbatim/x;
- ### Entornos verbatim write que conozco
- my @verbw_tmp = qw (scontents filecontents tcboutputlisting extikzpicture);
- my $verbatim_w = join "|", map quotemeta, sort { length $a <=> length $b } @verbw_tmp;
- $verbatim_w = qr/$verbatim_w/x;
- ### Función para crear el hash begin -> BEGIN, end -> END
- sub crearhash {
- my %cambios;
- for my $aentra(@_){
- for my $initend (qw(begin end)) {
- $cambios{"\\$initend\{$aentra"} = "\\\U$initend\E\{$aentra";
- }
- }
- return %cambios;
- }
- ### Función para eliminar repetidos
- sub uniq {
- my %seen;
- grep !$seen{$_}++, @_;
- }
- ### Función para restar
- sub array_minus(\@\@) {
- my %e = map{ $_ => undef } @{$_[1]};
- return grep( ! exists( $e{$_} ), @{$_[0]} );
- }
- ### Array y hash para los cambios
- my %iniciofin = (
- # begin/end para verbatim write
- '\begin{document}' => '\BEGIN{document}',
- '\end{document}' => '\END{document}',
- );
- my @noverbatimw; # tiene todo menos verbatim write
- push(@noverbatimw, @extr_tmp, @verb_tmp);
- @noverbatimw = uniq(@noverbatimw);
- my %reemplazo_en_write = crearhash(@noverbatimw);
- #print Dumper \%reemplazo_en_write; #__END__
- my @noverbatim; # tiene todo menos verbatim
- push(@noverbatim, @extr_tmp, @verbw_tmp);
- @noverbatim = uniq(@noverbatim);
- my %reemplazo_en_normal = crearhash(@noverbatim);
- #print Dumper \%reemplazo_en_normal; #__END__
- my $document = '
- \documentclass{article}
- % Usando filecontents
- \begin{filecontents*}{temp.tex}
- Aquí puede ir cualquier cosa escrita
- \begin{document} % cambia
- \begin{Verbatim} % cambia
- \end{preview} % cambia
- \begin{preview} % cambia
- \begin{PSTexample} % cambia
- \end{enumerate}
- \end{filecontents*} % cierra
- \usepackage{tikz,fvextra}
- \begin{document}
- Aquí inicia el documento real
- \begin{Verbatim}
- Aquí va cualquier cosa
- \begin{filecontents*} % cambia
- \begin{enumerate}
- \item First
- \begin{enumerate}
- \item Second
- \item Third
- \end{enumerate}
- \item Fourth
- \end{enumerate}
- \end{Verbatim} % cierra
- Aquí otro
- \begin{Verbatim}
- \end{filecontents*} % cambia
- Texto
- \end{Verbatim} % cierra
- Texto \begin{verbatim}
- % Inicia
- \begin{document} % cambia
- \begin{filecontents} % cambia
- \end{PSTexample} % cambia
- \begin{preview} % cambia
- % Termina
- \end{verbatim} % cierra
- Este lo sacaré
- \begin{PSTexample}
- % Esto es example 1
- \pspicture(4,6)
- \psset{unit=2cm}
- \pslineByHand[linecolor=red](0,0)(0,2)(2,2)
- (2,0)(0,0)(2,2)(1,3)(0,2)(2,0)
- \endpspicture
- \end{PSTexample}
- Este también lo sacaré
- \begin{pspicture}(4,6)
- \psset{unit=2cm}
- \pslineByHand[linecolor=red](0,0)(0,2)(2,2)
- (2,0)(0,0)(2,2)(1,3)(0,2)(2,0)
- \end{pspicture}
- Esto No lo sacaré
- \begin{nopreview}
- \begin{verbatim}
- \begin{filecontents} % cambia
- \begin{preview} % cambia
- \end{verbatim}
- \end{nopreview}
- Más texto
- Esto igual lo sacaré
- XXX\begin{preview}
- \begin{verbatim}
- \begin{filecontents} % cambia
- \begin{preview} % cambia
- \end{verbatim}
- \end{preview}YYYY
- \end{document}
- ';
- ### Divido por líneas y hacemos los cambios
- my @lineas = split /\n/, $document;
- my %replace = (%reemplazo_en_normal,%iniciofin);
- my $find = join "|", map {quotemeta} sort { length($a)<=>length($b) } keys %replace;
- my $DEL;
- for (@lineas) {
- if (/\\begin\{($verbatim\*?)(?{ $DEL = "\Q$^N" })\}/ .. /\\end\{$DEL\}/) {
- s/($find)/$replace{$1}/g;
- }
- if (/\\begin\{($verbatim_w\*?)(?{ $DEL = "\Q$^N" })\}/ .. /\\end\{$DEL\}/) {
- %replace = (%reemplazo_en_write,%iniciofin); #
- $find = join "|", map {quotemeta} sort { length($a)<=>length($b) } keys %replace;
- s/($find)/$replace{$1}/g;
- }
- }
- ### Unimos y miramos
- $document = join("\n", @lineas);
- say $document;
Coloreado en 0.007 segundos, usando GeSHi 1.0.8.4
Using latex Syntax Highlighting
- \documentclass{article}
- % Usando filecontents
- \begin{filecontents*}{temp.tex}
- Aquí puede ir cualquier cosa escrita
- \BEGIN{document} % cambia
- \BEGIN{Verbatim} % cambia
- \END{preview} % cambia
- \BEGIN{preview} % cambia
- \BEGIN{PSTexample} % cambia
- \end{enumerate}
- \end{filecontents*} % cierra
- \usepackage{tikz,fvextra}
- \BEGIN{document}
- Aquí inicia el documento real
- \BEGIN{Verbatim}
- Aquí va cualquier cosa
- \begin{filecontents*} % cambia
- \begin{enumerate}
- \item First
- \begin{enumerate}
- \item Second
- \item Third
- \end{enumerate}
- \item Fourth
- \end{enumerate}
- \END{Verbatim} % cierra
- Aquí otro
- \BEGIN{Verbatim}
- \end{filecontents*} % cambia
- Texto
- \END{Verbatim} % cierra
- Texto \BEGIN{verbatim}
- % Inicia
- \BEGIN{document} % cambia
- \begin{filecontents} % cambia
- \END{PSTexample} % cambia
- \BEGIN{preview} % cambia
- % Termina
- \END{verbatim} % cierra
- Este lo sacaré
- \BEGIN{PSTexample}
- % Esto es example 1
- \pspicture(4,6)
- \psset{unit=2cm}
- \pslineByHand[linecolor=red](0,0)(0,2)(2,2)
- (2,0)(0,0)(2,2)(1,3)(0,2)(2,0)
- \endpspicture
- \END{PSTexample}
- Este también lo sacaré
- \BEGIN{pspicture}(4,6)
- \psset{unit=2cm}
- \pslineByHand[linecolor=red](0,0)(0,2)(2,2)
- (2,0)(0,0)(2,2)(1,3)(0,2)(2,0)
- \END{pspicture}
- Esto No lo sacaré
- \BEGIN{nopreview}
- \BEGIN{verbatim}
- \begin{filecontents} % cambia
- \BEGIN{preview} % cambia
- \END{verbatim}
- \END{nopreview}
- Más texto
- Esto igual lo sacaré
- XXX\BEGIN{preview}
- \BEGIN{verbatim}
- \begin{filecontents} % cambia
- \BEGIN{preview} % cambia
- \END{verbatim}
- \END{preview}YYYY
- \END{document}
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
Using latex Syntax Highlighting
- \documentclass{article}
- % Usando filecontents
- \begin{filecontents*}{temp.tex}
- Aquí puede ir cualquier cosa escrita
- \BEGIN{document} % cambia
- \BEGIN{Verbatim} % cambia
- \END{preview} % cambia
- \BEGIN{preview} % cambia
- \BEGIN{PSTexample} % cambia
- \end{enumerate}
- \end{filecontents*} % cierra
- \usepackage{tikz,fvextra}
- \begin{document}
- Aquí inicia el documento real
- \begin{Verbatim}
- Aquí va cualquier cosa
- \BEGIN{filecontents*} % cambia
- \begin{enumerate}
- \item First
- \begin{enumerate}
- \item Second
- \item Third
- \end{enumerate}
- \item Fourth
- \end{enumerate}
- \end{Verbatim} % cierra
- Aquí otro
- \begin{Verbatim}
- \END{filecontents*} % cambia
- Texto
- \end{Verbatim} % cierra
- Texto \begin{verbatim}
- % Inicia
- \BEGIN{document} % cambia
- \BEGIN{filecontents} % cambia
- \END{PSTexample} % cambia
- \BEGIN{preview} % cambia
- % Termina
- \end{verbatim} % cierra
- Este lo sacaré
- \begin{PSTexample}
- % Esto es example 1
- \pspicture(4,6)
- \psset{unit=2cm}
- \pslineByHand[linecolor=red](0,0)(0,2)(2,2)
- (2,0)(0,0)(2,2)(1,3)(0,2)(2,0)
- \endpspicture
- \end{PSTexample}
- Este tambien lo sacaré
- \begin{pspicture}(4,6)
- \psset{unit=2cm}
- \pslineByHand[linecolor=red](0,0)(0,2)(2,2)
- (2,0)(0,0)(2,2)(1,3)(0,2)(2,0)
- \end{pspicture}
- Esto No lo sacaré
- \begin{nopreview}
- \begin{verbatim}
- \BEGIN{filecontents} % cambia
- \BEGIN{preview} % cambia
- \end{verbatim}
- \end{nopreview}
- Más texto
- Esto igual lo sacaré
- XXX\begin{preview}
- \begin{verbatim}
- \BEGIN{filecontents} % cambia
- \BEGIN{preview} % cambia
- \end{verbatim}
- \end{preview}YYYY
- \end{document}
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
No sé cómo hacer que lea el archivo y decida cuál cambio se debe efectuar primero o quizás una mejor forma de hacer esto.
Saludos.