Perl en Español

  1. Home
  2. Tutoriales
  3. Foro
  4. Artículos
  5. Donativos
  6. Publicidad
 

Función grep
Ir a página 1, 2  Siguiente
 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico
Mensaje Mar Jul 01, 2008 6:39 am
STM
Perlero Nuevo
Perlero Nuevo
Registrado: 01 Jul 2008
Mensajes: 14
Función grep Responder citando

Hola a todos Very Happy
Desearía hacerles una pregunta:
1-) Tengo un archivo del cual debo escoger solo ciertas líneas, cada línea queda dividida en cinco partes y yo trabajo solo con tres: $ip1, $ip3, $ip6, así que escribí

Perl:
open (IN, "BRA065.txt");
open(BRA, ">bra.txt")

foreach $bra (($ip1,$ip2,$ip3,$ip4,$ip5,$ip6) = split(" ", $_, 6)){
       @bras= grep(/w/,/area/,/spc/,$cmos)
write BRA


Uso la función grep para seleccionar las líneas que tienen cualquiera de las palabras spc, area o w para guardarlas en @bra pero él imprime la información contenida en $bra y no en @bra.

En realidad no sé cómo especificarle que imprima la información contenida en @bra
usando la función write (porque tengo un formato que respetar).

Muchas gracias de antemano a las personas que me puedan ayudar.
Hasta Luego.
Mensaje Mar Jul 01, 2008 6:57 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4034
Ubicación: Valladolid, España
Responder citando

Bienvenido a los foros de Perl en Español, STM.

Andas un poco perdido con la sintaxis, me parece a mí...

En el comentario hablas de la función @bra, pero en el código pones @bras.

grep(), en el código, está analizando la variable $cmos de la cual no sabemos de dónde viene. Ni siquiera estás comparando los valores de las variables $ip1, $ip3, $ip6.

Y de la pobre variable $bra, no sabemos para qué la usas, porque solo aparece una vez en el código.

No está claro qué es lo que quieres guardar en @bra: ¿los campos extraídos por split() o toda la línea?
Mensaje Mar Jul 01, 2008 7:31 am
STM
Perlero Nuevo
Perlero Nuevo
Registrado: 01 Jul 2008
Mensajes: 14
Responder citando

Hola,
lo siento, es que copié mal el código que tenía; el verdadero código es así:

Perl:
open (IN, "BRA065.txt");
open(BRA, ">bra.txt");

foreach $bra (($ip1,$ip2,$ip3,$ip4,$ip5,$ip6) = split(" ", $_, 6)){
       @bra= grep(/w/,/area/,/spc/,$bra);
write BRA


Muchas Gracias
Mensaje Mar Jul 01, 2008 7:46 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4034
Ubicación: Valladolid, España
Responder citando

Siguen faltando muchas pistas, pero una primera aproximación al problema podría ser
Perl:
open (IN, "BRA065.txt");
open(BRA, ">bra.txt");

($ip1,$ip2,$ip3,$ip4,$ip5,$ip6) = split;
@bra = grep { /w|area|spc/ } $ip1,$ip3,$ip6;

write BRA

* La línea ($_) que se supone que estará compuesta de campos separados por espacios en blanco, es dividida y nos quedamos con las 6 primeras partes
* Las partes que nos interesan entran en el grep y son filtrados por la expresión regular, que busca patrones de 'w', 'area' o 'spc'. Si alguno coincide, se van almacenando en @bra
* Y luego escribe el resultado, pero no sabemos qué aspecto tiene el formato para write(), así que eso ya depende de ti.

Se pueden abreviar las dos líneas en una:
Perl:
@bra = grep { /w|area|spc/ } ( split )[0,2,5];
Mensaje Mie Jul 02, 2008 2:07 am
STM
Perlero Nuevo
Perlero Nuevo
Registrado: 01 Jul 2008
Mensajes: 14
Responder citando

Hola de nuevo,
Ya ensaye el código que usted me envió pero él continúa imprimiendo todas las líneas del archivo original.

Esta vez envío el código completo de mi programa (no es muy grande, pero ya no es el mismo que yo tenía ayer). Ensayé varias sintaxis de la función grep pero nada funciona y no entiendo por qué.

Perl:
open (IN, "BRA065.txt");
open(BRA, ">bra065.txt");   


while (<IN>) {
  chomp;
       #while ($line=<IN>) {
       #foreach $bra_1 (($ip1,$ip2,$ip3,$ip4,$ip5,$ip6) = split(" ", $_, 6)){
       #@bra= grep{m/^[density_W, win, step, length, nalw]//}$bra_1;
       #($ip1, $ip2, $ip3,$ip4,$ip5,$ip6) = split(" ", $_, 6); 
       
       
       #foreach $bra_1 (($ip1,$ip2,$ip3,$ip4,$ip5,$ip6) = split(" ", $_, 6)){
       #@bra= grep{m/^[density_W, win, step, length, nalw]//}$bra_1;
       
       if (@bra eq "OD.W.1")
          {@bra= OD.WIDTH}
       if (@bra eq "OD.S.1")
          {@bra= OD.SPACE}
     
       #@bra = grep { /w|area|spc/ } ( split )[0,3,4];
       ($ip1,$ip2,$ip3,$ip4,$ip5,$ip6) = split;
       @bra = grep { /w|area|spc/ } $ip1,$ip4,$ip5;

 write BRA ;#"$bra\n"; #print bra

 
 }
 
 format BRA =
 @<<<<<<<  (  @<<<<<<<  @<<<<<< )
 $ip1,        $ip4,      $ip5     
 
.   
       #"$bra\n"; #print bra
}


Muchas gracias de antemano por su ayuda.
Mensaje Mie Jul 02, 2008 5:21 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4034
Ubicación: Valladolid, España
Responder citando

Si estás empezando con Perl, es muy recomendable que pongas
Perl:
use strict;
use warnings;
al principio del programa. Te avisará de cosas extrañas que pones en tu código.

Por ejemplo, las líneas
Perl:
       if (@bra eq "OD.W.1")
          {@bra= OD.WIDTH}
       if (@bra eq "OD.S.1")
          {@bra= OD.SPACE}

no tienen mucho sentido para mí. ¿Dónde se inicializa la variable @bra? ¿Qué valor devuelve la función OD.WIDTH? ¿Dónde está definida? Lo mismo para la función OD.SPACE.

Es más... estás intentando comparar un array con una cadena de caracteres:
Perl:
if (@bra eq "OD.W.1")
lo cual tampoco tiene mucho sentido (salvo que estés usando Perl5.10, pero en ese caso no estás usando el operador smart-match).

Para evitar que te muestre todas las líneas del fichero, te falta por saber qué líneas son las que quieres imprimir. Eso implica hacer una condición, que suponemos que es la que quieres hacer con el comando grep().

Esta es una opción (no probada):
Perl:
#!/usr/bin/perl
use strict;
use warnings;

# Nuestras variables
my ($ip1, $ip4, $ip5);

# Abrimos los ficheros
open (IN,  "<BRA065.txt") or die "$!\n";
open (BRA, ">bra065.txt") or die "$!\n";   

# Definimos el formato
format BRA =
 @<<<<<<<  (  @<<<<<<<  @<<<<<< )
 $ip1,        $ip4,      $ip5     

.

# Para todo el fichero
while ( <IN> ) {                                    # Leemos la línea
    ($ip1,undef,undef,$ip4,$ip5,undef) = split;     # La partimos
    if ( grep { /w|area|spc/ } $ip1,$ip4,$ip5 ) {   # Si tenemos algo realmente interesante
        write BRA;                                  # Lo imprimimos
    }
}

# Cerramos los ficheros
close IN;
close BRA;
Ya te digo que no lo he podido probar, sobre todo porque no sé muy bien como es el fichero de entrada y qué es lo que quieres sacar/filtrar, ya que los if que has puesto ahora me han despistado.
Mensaje Mie Jul 02, 2008 6:57 am
STM
Perlero Nuevo
Perlero Nuevo
Registrado: 01 Jul 2008
Mensajes: 14
Funcion grep Responder citando

Buenas Tardes,
Pues yo creía que el programa funcionaba de la siguiente forma:

Las variables ipXXXX se inicializan con la primera línea leída en el archivo BRA.txt y van cambiando continuamente de datos hasta que se termina de leer el archivo.

La idea es que yo debo leer el archivo, filtrar las líneas donde aparecen las palabras (w, area, spc) y guardarlas en el nuevo archivo bra.txt.

Con el if, yo pensaba hacer un reemplazo de datos porque hay líneas que tienen la frase OD.W.1 y yo quisiera que en el nuevo archivo esa frase quede OD.WIDTH (OD.W.1 no es una función, es una cadena de caracteres lo mismo que OD.SPACE).

Siento mucho molestar tanto.
Muchas Gracias. Very Happy
Mensaje Mie Jul 02, 2008 7:31 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4034
Ubicación: Valladolid, España
Responder citando

Entiendo lo del reemplazo, que puedes hacer así:

Perl:
s/OD\.W\.1/OD.WIDTH/g;
s/OD\.S\.1/OD.SPACE/g;


Con eso modificarás la variable $_, que contiene la línea que has leído en el while.

Ahora bien... ¿por qué hacer este reemplazo? En el fichero de salida van a salir 3 columnas, con los valores de los campos 1 4 y 5. Si en alguno de ellos aparecen los patrones (w, area o spc) (escritas así, en minúscula) entonces los graba. Pero si no, no.

Vamos, que no entiendo qué relación puede haber entre querer hacer un reemplazo, si ese reemplazo no va a salir en el fichero. ¿O es que sí debería salir? En ese caso, no está del todo explicado qué líneas son las que deseamos sacar fuera.

P.D.1: No es buena idea que los dos ficheros se llamen casi igual.

P.D.2:
Aquí nadie molesta, porque el que molesta, no está aquí.
Mensaje Mie Jul 02, 2008 7:47 am
STM
Perlero Nuevo
Perlero Nuevo
Registrado: 01 Jul 2008
Mensajes: 14
Responder citando

Buenas tardes.

Mi idea es que el remplazo se vea en el segundo archivo.

En realidad yo deseo hacer algo así:
yo leo el archivo de entrada, filtro las líneas donde aparece " w,spc,area" .

Como cada línea está dividida en seis tomo solo tres partes, las acomodo según mi formato y hago el reemplazo.

Al final tendré un archivo de tres columnas que en vez de tener w tendrá width y así sucesivamente con spc y area.

Muchas Gracias.
Mensaje Mie Jul 02, 2008 8:12 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4034
Ubicación: Valladolid, España
Responder citando

¡Ah! Pero es que eso cambia mucho la cosa...

Perl:
#!/usr/bin/perl
use strict;
use warnings;

# Nuestras variables
my ($ip1, $ip4, $ip5);

# Abrimos los ficheros
open (IN,  "<BRA065.txt") or die "$!\n";
open (BRA, ">bra065.txt") or die "$!\n";   

# Definimos el formato
format BRA =
 @<<<<<<<  (  @<<<<<<<  @<<<<<< )
 $ip1,        $ip4,      $ip5     

.

# Yo leo el archivo de entrada,
while ( <IN> ) {

    # Filtro las líneas donde aparece "w,spc,area"
    if ( /w|area|spc/i ) {

        # hago el reemplazo
        s/OD\.W\.1/OD.WIDTH/g;
        s/OD\.S\.1/OD.SPACE/g;

        # Como cada línea está dividida en seis tomo solo tres partes
        ($ip1,undef,undef,$ip4,$ip5,undef) = split;

        # las acomodo según mi formato
        write BRA;
    }
}

# Cerramos los ficheros
close IN;
close BRA;


Como ves, tu mismo has dado la solución al problema, salvo un detalle: había que hacer el reemplazo ANTES de hacer la división de la línea. Si lo hubiéramos hecho al revés, tendríamos que haber hecho el reemplazo por cada una de las 3 partes. Mejor hacerlo solo una vez.
Mensaje Mie Jul 02, 2008 8:48 am
STM
Perlero Nuevo
Perlero Nuevo
Registrado: 01 Jul 2008
Mensajes: 14
Responder citando

Muchas Gracias.
Muy amable, al fin entiendo.
Ahora podré adicionar e implementar más funciones.
Hasta Luego.
Mensaje Mie Jul 02, 2008 9:57 am
STM
Perlero Nuevo
Perlero Nuevo
Registrado: 01 Jul 2008
Mensajes: 14
Responder citando

Buenas Tardes.

He estado trabajando en el código pero resulta que le añadí más líneas al archivo fuente BRA.txt y ahora solo filtra las primeras líneas pero después deja pasar todo; en el archivo de salida uno obtiene una copia exacta del archivo de entrada; yo creo que es porque aparece el símbolo "#" y espacios en blanco al principio de algunas de las líneas del archivo de entrada.

¿Es que debo trabajar con if anidados?

Porque pareciera que él hace un buen filtraje hasta la parte donde encuentra un símbolo raro (algo diferente a una letra).

Muchas gracias.
Mensaje Mie Jul 02, 2008 3:11 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4034
Ubicación: Valladolid, España
Responder citando

El programa está perfecto para el caso de que el fichero de entrada conste de líneas con 6 o más campos de texto separados con espacios en blanco.

Si las líneas del fichero no siguen esa sencilla regla, entonces, split, falla.

Si cambias las condiciones del juego, debes cambiar las reglas del juego. O no hay juego.
Mensaje Mie Jul 02, 2008 3:33 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 4034
Ubicación: Valladolid, España
Responder citando

STM escribió:
yo creo que es porque aparece el símbolo "#" y espacios en blanco al principio de algunas de las líneas del archivo de entrada.

Si quieres filtrar esas líneas, puedes colocar
Perl:
next if /^#/;
después del while.
Mensaje Jue Jul 03, 2008 8:55 am
STM
Perlero Nuevo
Perlero Nuevo
Registrado: 01 Jul 2008
Mensajes: 14
Seleccion Responder citando

Hola, Buen día.

He visto que existen expresiones que detectan un carácter y lo eliminan, pero ¿si lo que se necesita es eliminar todas las palabras que contengan ese carácter? porque yo intenté esto:
Perl:
s/ lenght/ /g;
next if /^#/;
next if /^$/;
pero estas expresiones sirven para comparar una palabra dada, no un carácter.

Pero yo lo que deseo es detectar el carácter "<" y eliminar toda la línea.

Muchas gracias de antemano.
Hasta Luego
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico Todas las horas son GMT - 6 Horas
Ir a página 1, 2  Siguiente
Página 1 de 2



Powered by phpBB © 2001, 2005 phpBB Group