• Publicidad

Extraer palabras segun un patrón

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

Extraer palabras segun un patrón

Notapor Zeokat » 2008-07-24 10:43 @488

Me explico, tengo varias líneas en un fichero de la siguiente forma.

13caracteres:defaultnombre

De forma que una línea podría ser así:

13caracteres:defaultnombre213caracteres:defaultnombre113caracteres:defaultnombre0

Yo tengo que extraer las palabras y guardarlas en otro archivo de forma que en el archivo de salida se almacenen así:
Código: Seleccionar todo
nombre0:13carateres
nombre1:13carateres
nombre2:13carateres


Teniendo en cuenta que a nombrex le corresponden los 13 caracteres que tiene a su izquierda después de la palabra default.

También como se podría pensar, la línea siempre empieza por 13caracteres, pero a veces no es así. Por lo que yo tenía pensado buscar el último "default" de cada línea, leer los caracteres que están a su derecha (nombrex) y luego contar 14 caracteres a partir del "default" y almacenar los últimos 13 (ya que el carácter ':' no hace falta).

También tener en cuanta que los 13caracteres, no es una palabra siempre igual de 13 caracteres, sino que son 13 caracteres aleatorios.

La verdad es que no consigo abordar el problema, a ver si a alguien se le ocurre alguna idea. Quizás haya una manera más sencilla.

Gracias de antemano. :)
Zeokat
Perlero nuevo
Perlero nuevo
 
Mensajes: 125
Registrado: 2006-08-22 08:08 @380

Publicidad

Notapor Zeokat » 2008-07-24 13:46 @615

Lo probé en un archivo sencillo y parece funcionar:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -w
use strict;


my $dhd_file = $ARGV[0];
chomp($dhd_file);
open DATABASE,"$dhd_file" or die "The specified file cant be located.... \n";
my @database = <DATABASE>;
close(DATABASE);



my @valid_line;

foreach my $line (@database) {
    if ($line =~ /:default/) {
        push (@valid_line, $line);
    }
}


foreach my $line (@valid_line) {
    while (length($line) >= 14 && $line =~ /:default/) {
        chomp($line);
        my $posicion = rindex($line,":default");
        my @test = split(//,$line);
        my $posicion2 = scalar(@test);
        my $str = substr($line,$posicion-13,$posicion2);
        print $str,"\n";
        $line =~ s/$str//;
    }
}
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


El problema es cuando hay un carácter especial, por ejemplo
Código: Seleccionar todo
nombre44^


Se queda ahí hasta Out of memory... No sé cómo solucionarlo tampoco.
Zeokat
Perlero nuevo
Perlero nuevo
 
Mensajes: 125
Registrado: 2006-08-22 08:08 @380

Notapor explorer » 2008-07-24 15:40 @695

A mí me faltan algunos detalles...

¿De qué longitud son los nombres?

Dices que no siempre empieza por '13caracteres', entonces, en ese caso, ¿empieza por 'default' o por un nombre?
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 Zeokat » 2008-07-25 05:36 @275

Los nombres pueden variar su longitud, pero siempre tendrá como mínimo un carácter.

Dices que no siempre empieza por '13caracteres', entonces, en ese caso, ¿empieza por 'default' o por un nombre?

Me refería a que a veces no empieza por 13caracteres sino que a veces, por propio error en el archivo que estoy tratando algo ha salido mal (ajeno a mí) y empieza por una palabra que tiene menos de 13 caracteres.
Zeokat
Perlero nuevo
Perlero nuevo
 
Mensajes: 125
Registrado: 2006-08-22 08:08 @380

Notapor explorer » 2008-07-25 07:12 @342

Esta es mi solución.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

while ( <DATA> ) {
    while (
        /                           # Comienza la expresión regular
            (                       # Capturamos ...
                    ^ \w{1,12}      #   aquello que comienza la línea por menos de 13 caracteres
                |                   # o
                      \w{13}        #   aquello que tiene 13 caracteres
            )                       # ... como $1
            :default                # delante de un ':default'
            (                       # capturamos ...
                \w+                 #   un montón de caracteres
            )                       # ... como $2
            (?=                     # que precedan
                    $               #   al fin de línea
                |                   # o
                    \w{13} :default #   a otro conjunto de 13 caracteres con un ':default'
            )                       # Esto no lo capturamos ahora, pero sí la siguiente vuelta
        /simogx                     # Fin de la expresión regular
    ) {
        print "$2:$1\n";            # Pintamos lo capturado
    }
}
__DATA__
13caracteres0:defaultnombre013caracteres0:defaultnombre113caracteres0:defaultnombre2
13caracteres1:defaultnombre3
13caracteres2:defaultnombre413caracteres2:defaultnombre5
13caracteres:defaultnombre6
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Salida:
Código: Seleccionar todo
nombre0:13caracteres0
nombre1:13caracteres0
nombre2:13caracteres0
nombre3:13caracteres1
nombre4:13caracteres2
nombre5:13caracteres2
nombre6:13caracteres
No lo he probado mucho, pero al menos funciona con el ejemplo, que consiste en varias líneas, de longitudes diferentes, e incluso hay un caso de que no comienza por los 13 caracteres dichosos (la última línea).

Actualización: He repasado tu último mensaje. Parece que los nombres tienen caracteres extraños.

La siguiente variación captura todo tipo de caracteres, usando el mismo truco de antes, de utilizar los ':default' como anclas de posición.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

while ( <DATA> ) {
    while (
        /                           # Comienza la expresión regular
            (                       # Capturamos ...
                    ^ .{1,12}       #   aquello que comienza la línea por menos de 13 caracteres
                |                   # o
                      .{13}         #   aquello que tiene 13 caracteres
            )                       # ... como $1
            :default                # delante de un ':default'
            (                       # capturamos ...
                .+?                 #   un montón de caracteres
            )                       # ... como $2
            (?=                     # que precedan
                    $               #   al fin de línea
                |                   # o
                    .{13} :default  #   a otro conjunto de 13 caracteres con un ':default'
            )                       # Esto no lo capturamos ahora, pero sí la siguiente vuelta
        /iogx                       # Fin de la expresión regular
    ) {
        print "$2:$1\n";            # Pintamos lo capturado
    }
}
__DATA__
13caracteres0:defaultnombre013caracteres0:defaultnombre113caracteres0:defaultnombre2
13caracteres1:defaultnombre3
13caracteres2:defaultnombre413caracteres2:defaultnombre5
13caracteres:defaultnombre^^6
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
La diferencia principal es que le decimos explícitamente que busque por el nombre más corto (.+?) antes del siguiente patrón de coincidencias. Y eliminamos /s y /m de las opciones de la expresión regular, para que '.' no encuentre los finales de línea como si fueran un carácter más.
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 Zeokat » 2008-07-27 10:53 @495

Muchiiiiisimas gracias explorer. Lo probé y funciona bien.

Otra vez más, me has salvado el pellejo :)

Saludos.
Zeokat
Perlero nuevo
Perlero nuevo
 
Mensajes: 125
Registrado: 2006-08-22 08:08 @380


Volver a Básico

¿Quién está conectado?

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

cron