• Publicidad

Aplicar autoincremento solo si se cumple una condición

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

Aplicar autoincremento solo si se cumple una condición

Notapor sisifo80 » 2014-03-05 04:05 @212

Hola,

Estoy trabajando con archivos .xml y necesitaba hacer una modificación específica. Mi texto de entrada tiene el siguiente formato:

Sintáxis: [ Descargar ] [ Ocultar ]
Using xml Syntax Highlighting
  1.          <p t="opener">
  2.             <w id="23">
  3.               <o>Hola</o>
  4.             </w>
  5.             <w id="24">
  6.               <o>mundo</o>
  7.             </w>
  8.         </p>
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Es decir, cada palabra de un texto está delimitada por la etiqueta <o></o> y además lleva una numeración correlativa que no empieza en 1. Esta numeración aparece como valor del atributo id dentro de la etiqueta <w></w>. Finalmente, hay un nivel superior <p></p> que engloba párrafos enteros.

La salida que necesito tendría el siguiente formato:
Sintáxis: [ Descargar ] [ Ocultar ]
Using xml Syntax Highlighting
  1.          <p t="opener">
  2.             <w id="1">
  3.               <o>Hola</o>
  4.             </w>
  5.             <w id="2">
  6.               <o>mundo</o>
  7.             </w>
  8.         </p>
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Es decir, lo mismo que el anterior pero haciendo que la numeración correlativa comience en 1.

Creo que la solución sería usar el operador de autoincremento (++), pero la cosa se complica, porque necesitaba aplicar esa numeración desde 1 solo si la sección de párrafo lleva el atributo "opener" (como en la entrada anterior). Es decir, lo que no sé hacer en Perl es crear una condición tal que imprima la salida deseada con la numeración desde 1 solo a determinadas secciones de texto (por ejemplo, aquellas que están delimitadas por un <p></p> cuyo atributo es "opener").

Mi propuesta:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use warnings;
  2. use strict;
  3. $/ = undef
  4. my $numeración = 0;
  5. my $autoincremento = $numeración++;
  6. my $filename = shift;
  7. open F, $filename or die "Usa: $0 FILENAME\n";
  8. while(<F>) {
  9. if (/<p t=\"opener\".*?<\/p>/s) { #Si encuentras la sección <p t="opener"></p> (el punto (.) equivale a cualquier caracter incluyendo cambio de línea)
  10. s/<w id=\".*?\"/<w id=\"$autoincremento\"/ge #sustituye el valor de id por la variable $autoincremento
  11. }
  12. }
  13. close F;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Soy consciente de que en realidad no le estoy diciendo a Perl que aplique la sustitución solo en la sección deseada, simplemente le estoy diciendo que aplique esa sustitución a todo el documento si la condición es verdadera.

¿Alguna sugerencia que me permita aplicar la restricción y depurar mi propuesta?

Gracias.
sisifo80
Perlero nuevo
Perlero nuevo
 
Mensajes: 32
Registrado: 2013-11-20 07:30 @354

Publicidad

Re: Aplicar autoincremento solo si se cumple una condición

Notapor sisifo80 » 2014-03-05 17:55 @788

Había un par de errores en mi propuesta anterior. Quedaría así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use warnings;
  2. use strict;
  3. $/ = undef;
  4. my $numbering = 0;
  5. my $autonumbering = $numbering++;
  6. my $filename = shift;
  7. open F, $filename or die "Usa: $0 FILENAME\n";
  8. while(<F>) {
  9. if (/<p t=\"opener\".*?<\/p>/s) { #If the paragraph is <p t="opener"></p> (the dot (.) stands for every character, including \n)
  10. s/"<w id=\".*?\""/"<w id=\"$autonumbering\""/ge #replace the value of "id" by the variable $autonumbering
  11. }
  12. }
  13. close F;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
sisifo80
Perlero nuevo
Perlero nuevo
 
Mensajes: 32
Registrado: 2013-11-20 07:30 @354

Re: Aplicar autoincremento solo si se cumple una condición

Notapor explorer » 2014-03-05 19:16 @844

Esta es una manera:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use autodie;
  4.  
  5. my $archivo;
  6. open my $ARCHIVO, 'kk.xml';
  7. {
  8.         local $/;
  9.         $archivo = <$ARCHIVO>;
  10. }
  11. close $ARCHIVO;
  12.  
  13. my $contador = 1;
  14.  
  15. while ($archivo =~ m{<p t="opener">(.+?)</p>}sg) {
  16.         my($pos_inicio, $pos_final, $captura) = ($-[1], $+[1], $1);
  17.  
  18.         $captura =~ s{<w id="\K(\d+)}{$contador++}ge;
  19.  
  20.        substr($archivo, $pos_inicio, $pos_final - $pos_inicio) = $captura;
  21.  
  22.        pos($archivo) = $pos_inicio + length $captura;
  23.  
  24. }
  25.  
  26. print $archivo;
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: Aplicar autoincremento solo si se cumple una condición

Notapor sisifo80 » 2014-03-06 03:32 @189

Muchas gracias, explorer.
sisifo80
Perlero nuevo
Perlero nuevo
 
Mensajes: 32
Registrado: 2013-11-20 07:30 @354

Re: Aplicar autoincremento solo si se cumple una condición

Notapor sisifo80 » 2014-03-17 05:37 @276

Disculpa, explorer.

Este script que me has aconsejado me viene muy bien porque me permite hacer modificaciones a porciones de texto concretas. Es decir, "mientras el texto de entrada esté delimitado por... aplíquense las modificaciones...".

Por eso, como le estoy dando bastante uso, me gustaría entenderlo entero. ¿Podrías explicarme brevemente la lógica que está detrás de tu última línea de código? Me refiero a:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. pos($archivo) = $pos_inicio + length $captura;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

¿Está pensada para poder 'salir' del bucle while()?

Gracias.
sisifo80
Perlero nuevo
Perlero nuevo
 
Mensajes: 32
Registrado: 2013-11-20 07:30 @354

Re: Aplicar autoincremento solo si se cumple una condición

Notapor explorer » 2014-03-17 06:59 @332

Esa línea, no.

Lo que hace es reposicionar el "puntero" del motor de expresiones regulares, para que sepa que la próxima vez que tenga que analizar $archivo, debe hacerlo en esa determinada posición.

El proceso que hace el bucle es el siguiente:
  • se aplica un patrón a la variable $archivo, para buscar una coincidencia (m), de forma repetida (/g), en una cadena de texto que puede contener caracteres de fin de línea (/s)
  • si el motor de exp. reg. encuentra una coincidencia, salvaguardamos la posición inicial, y final de la captura, así como la propia captura del primer par de paréntesis del patrón
  • en la $captura, sustituimos (s) lo que coincida con el patrón -pero solo a partir de la marca '\K'- con la ejecución (/e) de un código Perl (el autoincremento del $contador, y devuelve su valor). Y esto, para toda la $captura (/g)
  • la $captura modificada (o no) es "insertada" en su posición anterior dentro de $archivo, acomodando espacio según haya cambiado su longitud (en más o en menos)
  • como la $captura puede haber cambiado de longitud, no podemos fiarnos de que en la siguiente vuelta el motor de exp. reg. detecte correctamente el siguiente patrón, así que "reposicionamos" el puntero a justo donde acabó la $captura. Así, sabemos que empezará a buscar el siguiente 'opener' a partir de ahí
Ahora que lo veo... sobran los paréntesis de la línea 18 :)
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: Aplicar autoincremento solo si se cumple una condición

Notapor sisifo80 » 2014-03-17 08:41 @403

¡Mil gracias! Me ha quedado clarísimo.
sisifo80
Perlero nuevo
Perlero nuevo
 
Mensajes: 32
Registrado: 2013-11-20 07:30 @354


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado

cron