• Publicidad

Reemplazar palabras en 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.

Reemplazar palabras en un archivo

Notapor pats » 2006-02-01 11:27 @519

Hasta ahora estoy empezando a trabajar en Perl...

Estoy haciendo un programa en Perl: leer un archivo y buscar las palabras, por ejemplo "toto" y cambiarlas por "titi"...

En general bastante simple... pero tengo un problema... mi programa no debería cambiar todos los "toto" por "titi", solo algunos...

Tengo dentro del archivo tres bloques de texto... y no quiero cambiar nada en los dos primeros bloques que comienzan cada uno por // y terminan con la palabra definition. Quisiera cambiar los "toto" por "titi" solo en el último bloque que comienza también por //

¿Alguna sugerencia?

¡¡¡Gracias!!!
pats
Perlero nuevo
Perlero nuevo
 
Mensajes: 3
Registrado: 2006-02-01 11:05 @503

Publicidad

Notapor monoswim » 2006-02-01 12:56 @580

...mmm... Yo empezaría por leer los tutoriales de expresiones regulares de este mismo sitio... Te ayudarán mucho...

Luego ver cómo hacer condicionales y cómo abrir archivos de texto, hay un par de tutoriales sobre el tema de base de datos tipo TXT...

Espero que te sirva.

Saludos
MonoSwim
Perl Programming Language
Avatar de Usuario
monoswim
Perlero nuevo
Perlero nuevo
 
Mensajes: 452
Registrado: 2003-11-18 16:13 @717
Ubicación: Buenos Aires

Notapor pats » 2006-02-01 13:33 @606

Vale... ¡¡¡Gracias...!!! :D

Lo leo y si tengo muchas dudas ¡¡¡ ya preguntaré !!!
pats
Perlero nuevo
Perlero nuevo
 
Mensajes: 3
Registrado: 2006-02-01 11:05 @503

Re: Reemplazar palabras en un archivo

Notapor explorer » 2006-02-01 14:44 @656

Como dices que el fichero tiene una cierta estructura, podemos aprovecharla para "extraer" el tercer párrafo.

Supongamos que el texto (texto.txt) sea:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
//
1kfj ljf skldsj fdsfs
fdskljf ldskjf lj
dskflj fljdslkjfdkfjh gkghd
fljg gjlj g fdg
definition
//
2lfdsj jdsfl kfj lf ds
f ldsfj skljf kfldjg df
+fdjh erojerordefsfd
lfdkj fljdg
definition
//
3lkjf ñj fsfdj totofd
totojfd gljtototfdg
fdg dkftotoldj fd gfd
dftototjg jgtotoj gdf
definition
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Cada párrafo empieza por "//" y termina por la palabra definition.

Dada esa estructura, podemos definir la variable especial "$/", que es la que define cómo es el separador de los registros de entrada, al valor "//".

De esa forma, cada vez que leamos un registro desde la entrada, nos dará todo el texto que va desde la última posición leída hasta el siguiente "//".

Hay que notar que el primer texto que leemos estará vacío, a causa de que precisamente el texto empieza por ese código. Es como si el primer registro estuviera vacío, así que empezaremos a leer desde el segundo párrafo.

Pero el que nos interesa es sólo el tercer párrafo (el cuarto que leemos). Lo que podemos hacer, para hacerlo más cómodo, es leer cada registro y meterlo en una posición de un array. Luego vamos al tercer elemento y cambiamos los toto por titi.

Finalmente, sacamos a pantalla el texto cambiado.

Este programa hace eso:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl

# Definimos cómo es el separador de registros
$/ = "//";

# Abrimos el fichero
open TXT, "<texto.txt" or die "No puedo abrir el texto.txt: $!\n";
@bloques = <TXT>;  # Leemos todo el fichero, registro por registro
close TXT;

# Editamos el tercer párrafo
# Recordar que el 0 está vacío, por lo que estará en la cuarta posición
# por lo que entonces será el registro con índice 3 (los arrays empiezan por 0)
$bloques[3] =~ s/toto/titi/g;

# Sacamos el resultado
print $bloques[3];
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


En una sola línea también se puede hacer:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
perl -e '$/=q(//); @bloques=<>; $bloques[3] =~ s/toto/titi/g; print $bloques[3]' texto.txt
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Otra forma sería leer sólo el párrafo que nos interesa y meterlo en una variable escalar:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$parrafo = (<TXT>)[3];
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
y luego seguir con la operación de cambio.

Es posible que el fichero sea muy grande, por lo que podríamos tener problemas al intentar leerlo todo de golpe (o ser una operación muy lenta). En ese caso, abriríamos el programa e iríamos línea a línea, procesando en el lugar correcto.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl

use warnings;
use strict;

# Contador de en qué bloque nos encontramos
my $en_parrafo = 0;

# Abrimos
open TXT,"<texto.txt" or die "No puedo abrir el fichero texto.txt: $!\n";

# Leemos por líneas
while ( my $linea = <TXT> ) {

    # Si es inicio de bloque, sumamos un párrafo más
    if ( $linea =~ m{^//} ) {
      $en_parrafo++;

      # En el caso de llegar al siguiente párrafo,
      # que no nos interesa seguir, salimos del bucle
      last if $en_parrafo == 4;
    }

    # Si estamos dentro del tercer bloque
    if ( $en_parrafo == 3 ) {

      # Hacemos el cambio del toto -> titi
      $linea =~ s/toto/titi/g;

      # Salida a pantalla del resultado
      print $linea;
    }
}

# Cerramos el fichero y nos vamos
close TXT;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Otra opción con la que poder jugar: si sabemos que la palabra "definition" va justo delante de la siguiente línea con "//", podríamos definir $/ como "definition\n//" y de esa manera ya podemos referirnos al tercer bloque como $bloques[2] en vez de $bloques[3].

Bueno... desde luego hay muchas formas de hacerlo.

A ver si alguien se anima con alguna más...
Última edición por explorer el 2008-08-05 17:56 @789, editado 2 veces en total
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

Notapor Perl user » 2006-02-01 15:25 @684

Yo siempre he insistido en que reescribir código que no necesariamente es mejor que el actual es reinventar el hilo negro...
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl

use strict;
use warnings;
use Tie::File; # Módulo incluido en el core de Perl por MJD

my $file;
tie $file, 'Tie::File', 'archivo.txt', recsep => '//';
$file[-1] =~ s/toto/titi/g;
untie $file;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Nota: El código lo escribí sin probarlo, pero estoy casi seguro que funciona. La idea pues, es que yo estoy a favor de la reutilización de buen código.

Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

listo...

Notapor pats » 2006-02-02 10:14 @468

Bueno... al final creo que lo logré... Aquí está lo que hice... Para mí, funciona... Lo probé y aparentemente está bien... No será muy buen código pero es el primero...

Leí los tutoriales que dijo monoswim y utilicé la idea que me dio explorer sobre los bloques... lo del buen código de Perl User la verdad lo entendí menos...

De hecho en general... necesitaba un programa en Perl... que modificará un archivo de acuerdo a un argumento específico... (¡¡¡obligatoriamente debo especificar un argumento...!!!) Debía cambiar las palabras ARGUMENTO por el argumento dado... pero no en todo el archivo sino en el último párrafo (cada párrafo comienza por // Library) y después salvar los cambios...

¿Pueden mirarlo a ver si les parece bien o si hay algo que pueda mejorar...?

¡¡Voilà..!!

¡¡Muchas Gracias...!!

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl


 if (@ARGV>0) {
 
 
 $/ = "// Library";
 

 open FILE, "<fichier" or die "On ne peut pas ouvrir le fichier: $!\n";
 @blocs = <FILE>; #On lit le fichier; bloc par bloc
 close FILE;
 

 # Pour savoir le nombre de blocs qu'on a
 $numblocs = scalar(@blocs);
 
 
 $a=1;
 #Pour trouver la position du dernier bloc
 $arg=$numblocs-$a;
 
 
 $blocs[$arg] =~ s/ARGUMENTO/$ARGV[0]/g;
 

 print @blocs;
 

 open FICH,">fichier" or die "On ne peut pas ouvrir le fichier: $!\n";

 foreach my $bloc (@blocs){
 print FICH "$bloc";
 }

 close(FICH);

 }

 else {
        print "Erreur : 1 argument requis\n";
 };
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
pats
Perlero nuevo
Perlero nuevo
 
Mensajes: 3
Registrado: 2006-02-01 11:05 @503

Notapor Perl user » 2006-02-02 10:24 @475

Estoy de acuerdo, está más que claro que no entendiste el código que puse, y también quedó muy claro que no entendiste la parte dónde digo "buen código".

Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor macgregor » 2006-02-02 11:04 @503

Hola.

Perl User, no te enfades :wink: tienes toda la razón al decir que no tiene sentido reinventar la rueda. Pero también tienes que entender que este es el foro básico y tu respuesta es muy técnica.

Es normal que alguien que empieza no entienda nada de lo que pusiste en tu respuesta, sobretodo si no sabe lo que es un módulo o se pierde cuando ve dos caracteres "raros" seguidos.

Todos hemos pasado por esa fase ( yo hay veces creo que todavía estoy en ella cuando veo algunas de tus respuestas o de las de explorer ;D ) ¡je,je,je!

De todas formas os pido a los dos que sigáis respondiendo de la forma que lo hacéis, se aprende bastante viendo vuestros mensajes y si no entiendo algo muy a menudo me pica la curiosidad de mirar documentación relacionada.

Un saludo a todos.
MACGREGOR [TM]
Avatar de Usuario
macgregor
Perlero nuevo
Perlero nuevo
 
Mensajes: 80
Registrado: 2004-12-09 07:32 @355
Ubicación: españa

Notapor Perl user » 2006-02-02 11:22 @515

¿Qué tal?

No, nunca me he enfadado, la mejor prueba es que sigo participando, esto sigue siendo un foro colectivo y nadie participa a la fuerza ( al menos eso creo ).

Y no, tampoco me molesta ver código de alguien que apenas inicia, el hecho de saber que hay más gente interesada vale la pena, no tengo nada en contra de ser novato y mucho menos de alguien que apenas comienza a programar.

Yo insisto, si nosotros los que según eso "sabemos", les damos como ejemplo código MALO, la gente que apenas inicia comenzará a copiar esos malos hábitos, y quitarlos después es más problema que desde un principio indicarle bien cómo debe hacer las cosas de manera correcta. Y más en este lenguaje, donde hay muchas trampas.

Yo opino que es muy bueno que todos participen, que todos se involucren y que todos presenten código, es la mejor manera de aprender, por eso es que siempre me la paso corrigiendo códigos, intentando utilizar estilos un poco más idiomáticos o más propios para el lenguaje, ¿según quién? Según cualquier persona que tenga mucha experiencia al usar el lenguaje, conozca detalladamente la sintaxis y tenga una fluidez idiomática en el mismo.

Si quieres verlo como un defecto, adelante, pero yo estoy a favor de muchas técnicas de ingeniería de software, y una de ellas es la reutilización de código, estoy completamente en contra de reinventar el hilo negro y es algo que no puedo evitar. Recuerda algo: lo que hace a Perl más fuerte nunca fue Perl como tal, lo es CPAN, es la comunidad, las contribuciones. Sin eso, Perl no fuera lo que es ahora.

Es muy bueno siempre intentar hacer las cosas por ti mismo, pero dejar cosas así en aplicaciones que están en producción puede traer efectos catastróficos.

En fin, esto sigue siendo un foro de opinión pública sobre Perl :)

Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924


Volver a Básico

¿Quién está conectado?

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