• Publicidad

Leer y reemplazar cadena de texto

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

Re: Leer y reemplazar cadena de texto

Notapor bvayap » 2013-06-04 06:39 @318

Hola de nuevo,

He conseguido buscar una cadena de texto, $agentN, en el cuarto campo de archivo.txt y, si existe, reemplazar todo el campo por una nueva cadena, $agentC:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;                                     # estilo estricto
  3. use warnings;                                   # activar advertencias
  4. use diagnostics;                                # diagnósticos de fallos
  5. use autodie;                                    # «Es mejor morir que regresar con deshonor» --proverbio Klingon
  6.  
  7. ### Variables
  8. my %redes;                                      # almacén con los cambios
  9.  
  10. ### Lectura del archivo CSV
  11. open my $CSV, '<', 'archivo.csv';
  12.  
  13. while (<$CSV>) {                                # para cada línea, hasta fin de archivo
  14.     chomp;                                      # quitamos caracteres fin de línea
  15.     my($nombre, $red) = split /[;]/;            # partimos la línea, extraemos columnas
  16.  
  17.     $redes{$red} = $nombre;
  18. }
  19.  
  20. close $CSV;
  21.  
  22. ### Procesado
  23. open my $ARCHIVO, '<', 'archivo.txt';           # Lectura del archivo a tratar
  24. open my $SALIDA,  '>', 'archivo.new.txt';       # Escritura del archivo resultado
  25.  
  26. my $agentN = 'Juan';
  27. my $agentC = '22333444X';
  28.  
  29. while (my $linea = <$ARCHIVO>) {                # para cada línea del $ARCHIVO
  30.     my(@campos) = split " ", $linea, 4;         # partir en cuatro cachos
  31.     my $IP = $campos[2];
  32.  
  33.     if (exists $redes{$IP}) {                   # si tenemos que cambiarla
  34.         $campos[2] = $redes{$IP};               # la cambiamos
  35.     }
  36.     if ($campos[3] =~ $agentN) {                # si existe $agentN
  37.         splice(@campos, 3,1,"\"$agentC\"\n");   # lo cambiamos por $agentC
  38.     }
  39.  
  40.     print $SALIDA join " ", @campos;            # guardamos el resultado
  41. }
  42.  
  43. close   $ARCHIVO;
  44. close   $SALIDA;
  45.  
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4


Tengo un par de dudas.

¿Hay alguna forma de no procesar las 6 primeras líneas de archivo.txt, ya que son una cabecera?

Tengo 4/5 valores para $agentN, cada uno con su correspondiente $agentC. En lugar de 4/5 condiciones, había pensado en definir un hash y utilizar un bucle foreach... ¿qué os parece?

Gracias por la ayuda,
bvayap
Perlero nuevo
Perlero nuevo
 
Mensajes: 31
Registrado: 2013-05-31 02:42 @154

Publicidad

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-04 07:01 @334

La línea 36 está mal escrita. Has puesto el operador de expresiones regulares (=~), pero la parte derecha no es un patrón.

Si quieres que sea un patrón, debes delimitarlo con '/'. O si se trata de una comparación de cadena de caracteres, debes usar el operador 'eq'.

Por otra parte, la línea siguiente es demasiado para lo que realmente quieres hacer... Vamos a ver...

La función splice() sirve para extraer, insertar o sustituir elementos de un array. En el caso que pones, estás extrayendo el tercer elemento, y lo sustituyes por otro nuevo contenido. Lo has complicado mucho... A lo mejor querías decir esto:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if ($campos[3]   eq  $agentN) {             # si la cuarta columna es igual a $agentN
  2.         $campos[3] = qq("$agentC"\n);           # lo cambiamos por un $agentC con comillas dobles y un avance de línea
  3.     }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Usamos el operador qq(), que realiza el mismo trabajo que las comillas dobles (interpolación), y así no tenemos que "escapar" las otras comillas dobles literales.

Para el problema de varias claves, lo normal es usar un hash, sí.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my %agentes = (
  2.     Juan    => '22333444X',
  3.     Antonio => '11111119H',
  4. );
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if (exists $agentes{$campos[3]}) {          # ¿Reconocemos ese agente?
  2.         $campos[3] = $agentes{$campos[3]};      # Lo sustituimos
  3.     }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Para saltar las seis primeras líneas puedes usar un bucle:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for (1..6) {
  2.     <$ARCHIVO>;
  3. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Pero, es mejor que si la cabecera se puede distinguir del resto, usar otra forma. Por ejemplo, si la cabecera comienza con '#', es mejor poner un
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     next if $linea =~ /^#/;
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: Leer y reemplazar cadena de texto

Notapor bvayap » 2013-06-04 09:57 @456

Hola explorer,

He cambiado la función splice() por el cambio de variable que indicabas haciendo uso de qq().

En cuanto a lo que comentas del hash, creo que no me he expresado bien. No es que el campo 4 de archivo.txt sea igual a $agentesN, sino que debe contenerlo y, si es así, se cambia por el valor de $agentesC. Por eso había empleado el operador =~, porque me encontré algún ejemplo que parecía indicar eso.

Pero el caso es que, con el hash, no entiendo muy bien cómo funciona; es decir, cómo hacer referencia al primer valor (lo que llamé $agentesN) o al segundo ($agentesC).

He probado el código que indicas pero no hace la sustitución en el 4º campo, entiendo que porque la línea 36 del código indica que ambos valores deben coincidir, no uno contener al otro, que es lo que necesitaría...

Muchas gracias y un saludo,
bvayap
Perlero nuevo
Perlero nuevo
 
Mensajes: 31
Registrado: 2013-05-31 02:42 @154

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-04 12:05 @545

Entonces, sí, sí que debes usar una expresión regular:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if ($campos[3] =~ m/$agentN/) {             # si la cuarta columna contiene $agentN
  2.         $campos[3] = qq("$agentC"\n);           # lo cambiamos por un $agentC con comillas dobles y un avance de línea
  3.     }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

El problema está en la solución con hashes: hay que hacer un bucle para encontrar la concordancia:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     for my $agentN (keys %agentes) {
  2.         if ($campos[3] =~ m/$agentN/) {             # si la cuarta columna contiene $agentN
  3.             $campos[3] = qq("$agentes{$agentN}"\n); # lo cambiamos por un $agentC con comillas dobles y un avance de línea
  4.             last;                                   # y salimos del bucle
  5.         }
  6.     }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Lo que hacemos es recorrer las claves del hash. Si alguna de esas claves se encuentra en la cuarta columna, hacemos la sustitución por el valor correspondiente a esa clave, y terminamos el bucle.

Si la cuarta columna tuviera un formato determinado, se podría hacer más óptimo.
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: Leer y reemplazar cadena de texto

Notapor bvayap » 2013-06-05 07:00 @333

Hola explorer,

Muchas gracias por tus respuestas y, sobre todo, por la paciencia con un novato :)

Ahora sí hace los cambios que necesito. Voy a ver si puedo adaptarlo a para otro archivo.txt que tendría un número de columnas variable, aunque la estructura de las cuatro primeras es como en este caso.

Lo dicho, gracias por tu tiempo y ayuda.
bvayap
Perlero nuevo
Perlero nuevo
 
Mensajes: 31
Registrado: 2013-05-31 02:42 @154

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-05 07:06 @337

Pues, en principio... no tendrías que hacer nada... :lol:
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: Leer y reemplazar cadena de texto

Notapor bvayap » 2013-06-05 10:57 @498

Pues no me funciona... El número de campos puede variar en cada línea y están separados por espacios. Pero hay campos que son un texto entre comillas con espacios en blanco y claro, en lugar de considerarlo un campo, lo parte en varios... :(
bvayap
Perlero nuevo
Perlero nuevo
 
Mensajes: 31
Registrado: 2013-05-31 02:42 @154

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-05 11:22 @515

Por eso en la línea 30 le puse un '4', al split().
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: Leer y reemplazar cadena de texto

Notapor bvayap » 2013-06-05 11:29 @520

Ya, entiendo que eso partía la línea en 4 campos. Pero en este .txt no sé cuántos campos hay.

¿Existe alguna forma de indicar que el texto que va entre comillas dobles se debe considerar un único campo?

Gracias.
bvayap
Perlero nuevo
Perlero nuevo
 
Mensajes: 31
Registrado: 2013-05-31 02:42 @154

Re: Leer y reemplazar cadena de texto

Notapor explorer » 2013-06-05 16:09 @715

A ver... no te hace falta...

Dices que las cuatro columnas siguen el esquema anterior, y que luego sigue una serie de columnas, que no sabemos cuántas son.

Entonces, lo que hay que hacer es modificar el split() cambiando el 4 por un 5.

El split() partirá la línea en 5 partes: las cuatro primeras contienen las cuatro columnas que conocemos, y el quinto campo contiene el resto de la $linea. El join() final la recompondrá.
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

AnteriorSiguiente

Volver a Básico

¿Quién está conectado?

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