Perl en Español

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

Extraer palabras segun un patrón

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico
Mensaje Jue Jul 24, 2008 9:43 am
Zeokat
Perlero Frecuente
Perlero Frecuente
Registrado: 22 Ago 2006
Mensajes: 115
Extraer palabras segun un patrón Responder citando

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:
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. Smile
Mensaje Jue Jul 24, 2008 12:46 pm
Zeokat
Perlero Frecuente
Perlero Frecuente
Registrado: 22 Ago 2006
Mensajes: 115
Responder citando

Lo probé en un archivo sencillo y parece funcionar:
Perl:
#!/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//;
    }
}


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


Se queda ahí hasta Out of memory... No sé cómo solucionarlo tampoco.
Mensaje Jue Jul 24, 2008 2:40 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 3841
Ubicación: Valladolid, España
Responder citando

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?
Mensaje Vie Jul 25, 2008 4:36 am
Zeokat
Perlero Frecuente
Perlero Frecuente
Registrado: 22 Ago 2006
Mensajes: 115
Responder citando

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

Cita:
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.
Mensaje Vie Jul 25, 2008 6:12 am
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 3841
Ubicación: Valladolid, España
Responder citando

Esta es mi solución.
Perl:
#!/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

Salida:
Código:
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.
Perl:
#!/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
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.
Mensaje Dom Jul 27, 2008 9:53 am
Zeokat
Perlero Frecuente
Perlero Frecuente
Registrado: 22 Ago 2006
Mensajes: 115
Responder citando

Muchiiiiisimas gracias explorer. Lo probé y funciona bien.

Otra vez más, me has salvado el pellejo Smile

Saludos.
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico Todas las horas son GMT - 6 Horas
Página 1 de 1



Powered by phpBB © 2001, 2005 phpBB Group