• Publicidad

Operar sobre TODOS los números de un archivo

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

Operar sobre TODOS los números de un archivo

Notapor charlygarcia » 2012-03-05 17:51 @785

Hola, amigos.

Tal vez sea muy fácil, pero la verdad, no sé cómo hacerlo y les agradecería una ayuda con lo siguiente:

Tengo un archivo de texto con la siguiente información (y pueden ser más polinomios); como la imagen a la cual se refiere ese mapa la he reducido a un 50% de su tamaño original.

Sintáxis: [ Descargar ] [ Ocultar ]
Using html4strict Syntax Highlighting
  1. <area shape="poly" alt="" coords="215,27,216,66,229,71,222,83,228,146,232,152,239,138,252,139,261,127,275,128,281,124,287,128,288,134,303,144,325,143,330,142,336,151,335,160,337,162,340,165,340,172,346,176,354,177,358,176,365,188,360,224,362,228,364,229,382,224,383,218,391,218,395,215,396,187,394,168,387,153,385,137,380,121,377,112,354,102,353,95,362,85,361,73,355,68,346,68,326,53,302,69,288,69,270,59,253,53,250,37,237,33,230,31,224,28,219,27,214,28" href="munic1.html" title="" />
  2. <area shape="poly" alt="" coords="232,153,243,143,260,140,261,131,269,129,278,132,282,128,284,130,284,136,299,146,324,148,329,147,332,152,333,166,336,165,337,176,346,181,356,180,361,189,357,221,355,225,336,215,325,213,317,207,303,207,293,212,286,213,264,198,262,199,259,211,258,213,243,214,233,206,225,206,225,197,228,191,225,178,226,170,233,163,234,157" href="munic2.html" title="" />
  3. <area shape="poly" alt="" coords="259,215,264,203,283,217,297,217,306,211,316,211,324,217,351,227,363,232,384,226,386,221,392,221,396,217,399,205,416,220,414,225,418,230,417,236,414,241,397,253,396,263,399,271,410,276,413,277,411,279,406,282,388,279,374,290,366,307,369,339,361,352,343,312,329,316,318,315,307,307,288,291,283,273,270,277,264,251,269,237,262,228" href="salamina.html" title="" />
  4. <area shape="poly" alt="" coords="401,202,420,193,421,215,427,223,429,224,457,178,467,178,467,172,484,160,507,159,516,147,537,161,536,171,529,182,548,182,548,189,543,198,550,239,556,247,566,247,569,248,569,254,575,254,578,258,572,269,576,280,573,286,565,283,557,288,547,285,538,294,530,292,526,300,511,303,504,313,503,315,495,313,484,324,476,317,471,307,469,278,446,256,431,266,424,281,413,270,406,270,400,263,411,246,420,237,419,223,415,214,403,206,400,202,402,201" href="munic3.html" title="" />
  5.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


¿Cómo debo reducir a un 50% ese imagemap? Tengo que hacer lo siguiente:

Abrir ese archivo y convertir cada número al porcentaje (50%) y dejarlo como un número entero; además volver a armar ese archivo nuevamente. Mejor dicho:

"Abrir el archivo y tomar cada número y dividirlo entre dos (50%) y guardar el archivo; puede ser con otro nombre."

En archivo2.txt debe estar el mismo formato de archivo1.txt pero con cada número dentro del archivo dividido entre 2. Todo lo demás debe quedar igual.


La verdad he pensado en abrir el archivo y tomar el archivo línea a línea y hacerle algún procedimiento, pero no me imagino qué hacerle y sé que es largo.

La pregunta :

¿Alguien sabe cómo hacer esto con una expresión regular o de alguna manera?

Les agradezco cualquier comentario o sugerencia o cualquier fragmento de código.

Gracias
Carlos García
[text]¿Cómo lograr que no se seque una gota de agua? Arrojándola al mar. [/text] - Nota: Este tag no se puede utilizar en firmas.Samsara
Avatar de Usuario
charlygarcia
Perlero nuevo
Perlero nuevo
 
Mensajes: 54
Registrado: 2009-03-06 23:16 @011

Publicidad

Re: Operar sobre TODOS los números de un archivo

Notapor explorer » 2012-03-05 19:05 @837

Realmente... no hay que operar sobre TODOS los números del archivo, sino solo los que pertenecen al atributo coords. Fíjate que en cada línea hay un número en los atributos href, y no queremos que se número cambie.

Esta es una primera solución, que se ejecuta desde la línea de comandos:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
perl -p -i'.bak' -E 'if (/<area shape="poly"/) { s{(\d+)(,|")}{int($1/2).$2}ge }' code_29971.txt
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4

  • code_29971.txt es el nombre del archivo que queremos modificar
  • Usamos la opción -p para que Perl abra el archivo y nos mande una línea cada vez
  • Con la opción -i indicamos que el archivo original lo guardaremos con la extensión '.bak', mientras que crearemos una versión nueva del archivo, en que haremos unas modificaciones
  • Las modificaciones están en la misma línea de comando, y por eso ponemos la opción -E, que precede al mini-programa de Perl de una línea que queremos ejecutar por cada línea del archivo original
  • Si la línea que hemos leído contiene '<area shape="poly"' entonces vamos a hacer una operación de sustitución (s///)
  • La sustitución se hará sobre todos los números (\d+) de la línea, que estén seguidos, bien por una coma (,), o (|) por las comillas dobles ("). Si te fijas, todos los números que nos interesan de la línea cumplen con ese patrón. Entonces, el número es capturado en $1, mientras que la coma o la comilla doble, en $2, por acción de los paréntesis de captura
  • Cuando encontramos un número, lo que hacemos es ejecutar un trozo de código Perl (por eso ponemos la opción /e al operador de sustitución)
  • La operación es dividir $1 por 2, sacar la parte entera, y concatenarle $2, que, recordemos, era la coma o comilla doble que seguía al número
  • Y esto lo repetimos para todos los números de la línea, con la ayuda de la opción /g
  • Todas las operaciones se realizan en la variable por defecto $_ (que no se ve), por lo que, efectivamente, estamos leyendo y transformando líneas

Se ve la "trampa" enseguida:
  • Necesitamos que todo la marca <area ... /> esté en una sola línea
  • Las coordenadas numéricas deben estar siempre seguidas por coma o comillas dobles. Si no, fallará en ese número
Si esto no se cumple, no funcionará el programa.

Esta es otra forma, más larga, pero más fácil de entender:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use File::Slurp;
  3.  
  4. my @html = read_file('code_29971.txt');                     # leemos el archivo
  5.  
  6. for my $linea (@html) {                                     # para cada línea...
  7.     if ($linea =~ /coords="(.+?)"/) {                       # si la línea es interesante
  8.         my $coordenadas = $1;                               # sacamos sus coordenadas
  9.         my @coordenadas = split /,/, $coordenadas;          # que están separadas por comas
  10.         for my $coordenada (@coordenadas) {                 # para cada coordenada...
  11.             $coordenada = int($coordenada / 2);             # la dividimos por dos
  12.         }
  13.         $coordenadas = join ",", @coordenadas;              # recomponemos la cadena de coordenadas
  14.         $linea =~ s/coords=".+?"/coords="$coordenadas"/;    # y la ponemos en lugar de la antigua
  15.     }
  16.     print $linea;
  17. }
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4

La operación de división entera entre dos también se puede hacer así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.             $coordenada >>= 1;                              # la dividimos por dos
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
(Usamos el operador de desplazamiento bit hacia la derecha, desplazando los bits una posición)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14482
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Operar sobre TODOS los números de un archivo

Notapor charlygarcia » 2012-03-06 00:16 @053

Muchas gracias.

No sé por qué no pude instalar los módulos necesarios en esta máquina y me toco hacerlos casi que a mano, sin módulos ni expresiones regulares.

Gracias a la idea que me dio el código 2 de explorer.

De cualquier modo quisiera compartir lo que hice y muchas gracias a explorer.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $abrir = "mapaxxx.txt";                # archivo con el mapa original
  2. open(abrir);
  3. @arreglo = <abrir>;
  4. close(abrir);
  5.  
  6. $FILE = "mapaxxx2.txt";                #archivo donde quedara el mapa convertido con las coordenadas a la mitad
  7. open( archivconf, ">" . $FILE );
  8. flock( archivconf, 2 );
  9.  
  10. foreach (@arreglo) {
  11.  
  12.     #@dp=split(/::/,$_);
  13.     $linea = $_;
  14.  
  15.     if ( $linea =~ /coords="(.+?)"/ )  # si la línea es interesante
  16.     {
  17.  
  18.         #print("hola");
  19.         @elementos = split( /,/, $_ );
  20.         print( "$elementos[0]  $elementos[1] numelementos  " . scalar(@elementos) . " \n" );
  21.         @primeros = split( /coords="/, $elementos[0] );
  22.         $primeros[1] = int( $primeros[1] / 2 );
  23.         $linea2 = $primeros[0] . "coords=\"" . $primeros[1];
  24.  
  25.         for ( $i = 1; $i < scalar(@elementos); $i++ ) {
  26.  
  27.             $a      = ( $elementos[$i] / 2 );
  28.             $linea2 = $linea2 . "," . int($a);
  29.         }
  30.  
  31.         @ultimos = split( /" href=/, $elementos[ ( scalar(@elementos) - 1 ) ] );
  32.         $ultimos[0] = int( $ultimos[0] / 2 );
  33.         $linea2 .= "\" href=" . $ultimos[1];
  34.  
  35.     }
  36.  
  37.     #$linea2.="\n";
  38.     print archivconf ($linea2);
  39. }
  40. flock( archivconf, 8 );
  41. close(archivconf);
  42.  
Coloreado en 0.005 segundos, usando GeSHi 1.0.8.4
Última edición por explorer el 2012-03-06 07:22 @349, editado 1 vez en total
Razón: Formateado de código con Perltidy
[text]¿Cómo lograr que no se seque una gota de agua? Arrojándola al mar. [/text] - Nota: Este tag no se puede utilizar en firmas.Samsara
Avatar de Usuario
charlygarcia
Perlero nuevo
Perlero nuevo
 
Mensajes: 54
Registrado: 2009-03-06 23:16 @011

Re: Operar sobre TODOS los números de un archivo

Notapor explorer » 2012-03-06 08:01 @376

Mejor así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. $abrir = "mapaxxx.txt";                         # archivo con el mapa original
  3. open(abrir);
  4. @arreglo = <abrir>;
  5. close(abrir);
  6.  
  7. $FILE = "mapaxxx2.txt";                         # archivo donde quedará el mapa convertido con las coordenadas a la mitad
  8. open( archivconf, ">" . $FILE );
  9. flock( archivconf, 2 );
  10.  
  11. for $linea (@arreglo) {
  12.  
  13.     if ( $linea =~ /coords="(.+?)"/ ) {         # si la línea es interesante
  14.  
  15.         @elementos = split( /,/, $1 );          # partimos las coordenadas
  16.  
  17.         for $elemento (@elementos) {
  18.             $elemento = int($elemento / 2);     # las dividimos entre 2
  19.         }
  20.                                                 # nuevas coordenadas
  21.         $nuevas_coordenadas = join ',', @elementos;
  22.                                                 # sustituyendo a las anteriores
  23.         $linea =~ s/coords=".+?"/coords="$nuevas_coordenadas"/;
  24.     }
  25.  
  26.     print archivconf $linea;
  27. }
  28.  
  29. flock(archivconf, 8);
  30. close(archivconf);
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

A propósito... creo que es la primera vez que veo a alguien usar una de las formas más extrañas que permite open(). Me refiero al open() de la línea 3.

perlfunc dice:
Si EXPR se omite, la variable escalar global (a nivel de paquete) del mismo nombre que el IDENTIFICADOR_ARCHIVO contiene el nombre del archivo.
(Tenga en cuenta que las variables léxicas -las declaradas con "my" o "state"- no servirán para este propósito; así que si está usando "my" o "state", especifique EXPR en su llamada a open.)

Una nota más: el bucle for() de la línea 17 funciona de la siguiente manera: cada elemento de @elementos no es copiada en $elemento, si no que $elemento contiene un "alias" (como una especie de referencia) a cada elemento de @elementos.

De esta manera, todo cambio que le hagas a $elemento dentro del bucle queda reflejado en el elemento correspondiente del array @elementos. Esa es la razón por la cual no necesitamos copiar o almacenar el valor de $elemento una vez modificado: porque ya está modificado el elemento dentro del array.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14482
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Operar sobre TODOS los números de un archivo

Notapor charlygarcia » 2012-03-06 11:01 @501

Muchas gracias, explorer.

Como siempre tus buenos comentarios hablan de tu buena formación.

Y la colaboración que nos das exige más compromiso con la calidad de nuestros códigos.

Muchas gracias nuevamente.
[text]¿Cómo lograr que no se seque una gota de agua? Arrojándola al mar. [/text] - Nota: Este tag no se puede utilizar en firmas.Samsara
Avatar de Usuario
charlygarcia
Perlero nuevo
Perlero nuevo
 
Mensajes: 54
Registrado: 2009-03-06 23:16 @011


Volver a Básico

¿Quién está conectado?

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