• Publicidad

Extraer varias líneas delimitadas por dos líneas especiales

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

Extraer varias líneas delimitadas por dos líneas especiales

Notapor Anthares » 2009-03-29 11:04 @502

Hola nuevamente :P

Estoy viendo cómo hacer lo siguiente:

Supongamos que me pueden pasar desde la entrada estándar varias líneas del estilo:
Código: Seleccionar todo
BEGIN
linea1
linea2
linea3
...
lineaN
END


Este bloque se puede repetir varias veces y puede haber texto fuera de estos bloques.

Ahora bien, si yo quiero tomar todas las líneas de la entrada estándar, guardarlas por ejemplo en un string (eso sé cómo hacerlo) luego para cada bloque de la forma anterior extraer las líneas que están entre BEGIN y END.

Es decir, si tengo:
Código: Seleccionar todo
BEGIN
pepe como helado
jojo jojo
END
esto no me interesa1
esto no me interesa2
....
esto no me interesaN
BEGIN
esta es otra linea
END


Quiero imprimir solo esto:
Código: Seleccionar todo
pepe como helado
jojo jojo
esta es otra linea


Es decir, que lo que esté fuera de los bloques BEGIN y END lo ignoro.

Claro que para empezar lo quise hacer con un solo bloque y sin pensar en más nada y luego si cuando me salga hacerlo para el caso que expuse antes.

Hice esto pero no dio resultado :S
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
@array = <STDIN>;
#$_ =join("",@array);
m/((^BEGIN)(.*)(^END)/m;
print "$2\n";
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Acá lo que quería hacer es simplemente considerar que tengo el primer bloque y extraer
Código: Seleccionar todo
pepe como helado
jojo jojo


Porque con el m/ hago chequeo de patrón en la tira $_ y con el /m digo que contiene muchas líneas.
Los ^ al BEGIN y al END se los pongo por que siempre siempre siempre el BEGIN y END arrancan en una nueva línea.

Claro algo se me está pasando por alto y lo más seguro que esté diciendo una grosería con el código que puse pero por ahora no se me prendió la :idea: y sigo viendo sobre el tema.

Pero si algún alma buena me da una idea :roll: me vendría muy bien :P

Gracias y saludos :o
Anthares
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2007-04-30 07:18 @346

Publicidad

Notapor explorer » 2009-03-29 12:09 @548

Con el operador rango es posible sacar fácilmente las líneas que te interesan.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
open FICHERO, '<', 'kk.txt';
while (<FICHERO>) {
    if (/BEGIN/ .. /END/) {
        print if ! /^(?:BEGIN|END)/;
    }
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Ahora bien, si lo quieres hacer con expresiones regulares,
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
open FICHERO, '<', 'kk.txt';
undef $/;
my $fichero = <FICHERO>;
while ($fichero =~ /BEGIN\n (.*?) END\n/smgx) {
    print $1;
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Fíjate que he cambiado el valor de $/ para poder leer todo el fichero de golpe, en lugar de una línea por elemento de un arreglo.

Así podemos aplicar la expresión regular a todo el fichero, con la ayuda de /s. Repetimos cada encuentro con la ayuda de /g. /m está por adorno, aunque realmente es siempre recomendable ponerlo con /s. Y /x es para hacer más legible la expresión regular poniendo espacios en blanco.
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

Notapor Anthares » 2009-03-29 14:46 @657

¡¡¡ Impecable :P !!! Muchas, muchas gracias. Me ayudó muchísimo. Perdón por demorar en contestar :roll:

Saludos :!: :!:
Anthares
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2007-04-30 07:18 @346

Notapor kidd » 2009-03-30 13:04 @586

explorer escribiste:Fíjate que he cambiado el valor de $/ para poder leer todo el fichero de golpe, en lugar de una línea por elemento de un arreglo.


El único comentario que haría, es que lo más conveniente al cambiar el valor de esta variable, y en su caso cualquier variable especial de Perl, es localizarlas.

La razón de esto es para evitar que por olvidar restablecer la variable a su valor por defecto, más adelante tengamos comportamientos que no deseeamos.

Así que yo haría el ejemplo de la siguiente manera:


Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
open my $FICHERO, '<', 'kk.txt';

#Con el bloque do localizamos la variable $/
my $fichero = do { local $/; <$FICHERO> };

close $FICHERO;

while ($fichero =~ /BEGIN\n (.*?) END\n/smgx) {
    print $1;
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Uriel Lizama Perl programmer fundador de Perl en Español
Perl Programming Language
Avatar de Usuario
kidd
Creador de Perl en Español
Creador de Perl en Español
 
Mensajes: 1166
Registrado: 2003-10-15 16:52 @744
Ubicación: México

Notapor Anthares » 2009-03-30 16:21 @723

Gracias por todas las respuestas :P muy buenas :!:

Saludos :wink:
Anthares
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2007-04-30 07:18 @346

Otro caso

Notapor Anthares » 2009-04-04 15:01 @667

Hola :P

Quería hacer algo similar a lo anterior, pero poniendo un poco más de complejidad.

Supongamos que el texto a analizar esta formado por cierto patrón que se repite y que de este patrón quiero analizar ciertas partes.

Por ejemplo, el patrón que siempre se va a repetir es este:

Código: Seleccionar todo
VAR linea1
linea2
....
lineaN
BEGIN linea_comentario
otras_lineas_1
otras_lineas_2
....
otras_lineas_N
END otra_linea_comentario



Es decir, que el bloque siempre empieza con un VAR que siempre siempre está al comienzo de línea.

A este VAR puede ir en la misma línea acompañado de texto (lo que yo le llame linea1) y luego después de él puede venir tantas líneas como quiera.

Luego viene el BEGIN que al igual que el VAR en la misma línea del BEGIN puede venir más texto. También después del BEGIN puede haber más líneas (a las que yo le llame otras_lineas_1, etc...)

Luego el bloque finaliza con un END con otra_linea_comentario que esto puede ser cualquier texto que completa la línea del END y una línea en blanco me indica que terminó el bloque, esto por ejemplo me sirve que ya que texto END puede estar contenido como texto dentro de las líneas que están entre el BEGIN Y END, pero el que realmente cierra un bloque es el que va seguido de una línea en blanco.

¡¡¡ Y por fin !!! lo que me gustaría hacer :roll: es contar cuántos de estos bloques hay y por cada bloque cuantas líneas entre el BEGIN y END hay.

Acá va uno:

Código: Seleccionar todo
VAR int x
string s
BEGIN pepe
 x = x +1
 s = "begin jojojo"
 println(s+" que paso???")
END end del programa principal

VAR int y

BEGIN funcion2
println(y)
END fin de funcion2


Entonces yo quisiera dar una salida como:

Código: Seleccionar todo
Bloque1 cantidad de lineas 3
Bloque2 cantidad de lineas 1



Ya sé :oops: que mi ejemplo es muy rebuscado pero quiero analizar a fondo con Perl un texto que tenga una estructura más compleja como este caso; es ya para mi complejo :P

Traté de hacer algo similar a lo que me habían ayudado la otra vez pero ahora con todo esto que le agregué.

Pero nada de lo que hago anda bien :oops: ¡¡¡ ya todo el texto se me mete en la primera búsqueda dentro del patrón de busqueda !!!

Claro, el modificador s me hace que el '.' coincida con "\n" inclusive; y si pongo algo '.*' los "\n" entran ahí; entonces se complica mucho decir que los bloques se limitan por un "\n".

La verdad me puse esta meta pero no me sale nada.

Lo voy a seguir pensando pero dejo esto por si me quieren dar una idea :P

¡¡ Saludos !!
Anthares
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2007-04-30 07:18 @346

Notapor explorer » 2009-04-04 16:35 @733

He puesto esta entrada como ejemplo:
Código: Seleccionar todo
VAR int x
string s
BEGIN pepe
 x = x +1
 s = "begin jojojo"
 println(s+" que paso???")
END end del programa principal

VAR int y

BEGIN funcion2
println(y)
END falso
END fin de funcion2


He puesto una fila END en el segundo bloque para contemplar el caso que comentas de que pueda existir una fila así antes del END del bloque.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
        1 #!/usr/bin/perl
        2 #
        3 use strict;
        4 use warnings;
        5 use diagnostics;
        6
        7 my $linea_anterior = '';
        8 my $num_bloques    = 'Bloque1';
        9 my $en_bloque;
       10 my $en_bloque_begin;
       11
       12 while (<>) {
       13     chomp;
       14
       15     if ($en_bloque = (/^VAR/ .. (($linea_anterior =~ /^END/) and $_ eq '' ))) {
       16         $en_bloque_begin = /^BEGIN/ .. ($en_bloque =~ /E0/);
       17     }
       18
       19     if ($en_bloque =~ /E0/) {
       20         my ($num_lineas) = $en_bloque_begin =~ /(\d)/;
       21         $num_lineas -= 3;
       22         print "$num_bloques cantidad de líneas $num_lineas\n";
       23         $num_bloques++;
       24     }
       25
       26     $linea_anterior = $_;
       27 }
       28
       29 __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Sale:
Código: Seleccionar todo
Bloque1 cantidad de líneas 3
Bloque2 cantidad de líneas 2


No sé si funcionará en todos los casos, pero al menos funciona con el ejemplo.

Hay que ejecutarlo pasándole el fichero como argumento.

El funcionamiento lo he basado en el operador rango, pero es casi mejor hacerlo con un intérprete de lenguajes (parser), ya que el ejemplo que has puesto parece que es un trozo de programa de ordenador.

  • En la línea 15 controlamos si estamos dentro un bloque VAR
  • En la línea 16 controlamos si estamos dentro de un bloque BEGIN
  • En la 19 miramos a ver si hemos llegado al final del bloque VAR, para pintar cuántas líneas hemos encontrado
  • En las líneas 20 y 21 calculamos cuántas líneas tiene el bloque BEGIN
  • Y lo imprimimos en la 22...
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

Notapor Anthares » 2009-04-04 16:41 @736

Muchas gracias :P ¡¡¡¡ realmente impecable la respuesta y ademas siempre hay una pronta respuesta !!! :wink: ¡¡¡ graciassss !!!
Anthares
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2007-04-30 07:18 @346

Notapor explorer » 2009-04-04 16:43 @738

NO. No es impecable: el programa no sirve de nada si hay fallos de sintaxis en el fichero de entrada.

Es mejor hacer un parseador.
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

Notapor Anthares » 2009-04-04 16:54 @746

Pero me sirve de base para seguir pensándolo :P y con eso para mi ya es mucho. Por eso muchas gracias.
Anthares
Perlero nuevo
Perlero nuevo
 
Mensajes: 26
Registrado: 2007-04-30 07:18 @346

Siguiente

Volver a Básico

¿Quién está conectado?

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