• Publicidad

Expresión regular específica

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

Expresión regular específica

Notapor carlosss » 2010-02-11 05:14 @259

Buenos días a todos, estoy empezando a usar expresiones regulares en Perl y no sé cómo podría hacer una cosa que os paso a contar.

Tengo un fichero plano con la siguiente estructura en cada fila:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
NOMBRE DNI IDENTIFICADOR COLOR LOCALIDAD NOMBRE DNI IDENTIFICADOR COLOR LOCALIDAD
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Cada campo va separado por al menos 3 espacios
NOMBRE: cualquier carácter incluido espacio
DNI: 9 letras o números **** puede no aparecer y en su lugar aparecerían 9 espacios *****
IDENTIFICADOR: (dos caracteres)(al menos un espacio)(9 caracteres)(al menos un espacio)(1 o 2 caracteres)
COLOR: cualquier carácter incluido espacio
LOCALIDAD: cualquier carácter incluido espacio

Ejemplos de registro:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
RAUL GARCIA RODRIGUEZ     Z4385964      W3 436547873 0        AZUL CLARO        MIRANDA DE EBRO
CARLOS SANZ           43645342      43     324543453     34     AMARILLO           SEVILLA
LUIS ANTONIO RUIZ                       33     323KJ5434    5     AMARILLO      VALENCIA
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Como he indicado al principio, en cada línea vendrían dos registros seguidos separados por al menos 3 espacios

Sólo me interesan los que en el campo color aparezca 'AMARILLO' o 'ROJO'
Los campos que quiero guardar para su posterior tratamiento (en las variables $1 $2 ...) son NOMBRE, DNI y COLOR.

El problema se me plantea debido a que el DNI puede estar o NO.

Si sabéis alguna manera de hacerlo os agradecería vuestra ayuda.

Gracias.
carlosss
Perlero nuevo
Perlero nuevo
 
Mensajes: 1
Registrado: 2010-02-11 04:48 @242

Publicidad

Re: Expresión regular específica

Notapor explorer » 2010-02-11 07:15 @344

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

El asunto es algo complejo, ya que los separadores son a su vez separadores dentro de los campos.

Hay que utilizar técnicas de eliminación del backtraking para, en el caso del DNI, quedarnos con el mejor caso posible.

Otro tema curioso es que cada línea tenga dos registros, pero bueno... cosas más raras hemos visto, ¿no? :)

La siguiente solución me funciona con los ejemplos que he colocado en la sección DATA. Supongo que habrá mejores formas de hacer lo mismo.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. ## Definimos la gramática
  7. my $sep       = qr/ {3,}/;
  8. my $texto     = qr/((?:\w| {0,2}(?=\w))+)/;
  9. my $nombre    = $texto;
  10. my $dni       = qr/( {9}?| {0,8}\w{1,9})/;
  11. my $ident     = qr/(\w\w +.{9} +\w\w?)/;
  12. my $color     = $texto;
  13. my $localidad = $texto;
  14. my $registro  = qr/$nombre $sep $dni $sep $ident $sep $color $sep $localidad/x;
  15.  
  16. ## Procesamos
  17. while (<DATA>) {
  18.     chomp;
  19.    
  20.     /^ $registro $sep $registro /x;              # dos registros separados por cada línea
  21.  
  22.     next if $4 ne 'AMARILLO'  and  $4 ne 'ROJO'; # solo nos interesan dos colores
  23.  
  24.     print "[$1][$2][$3][$4][$5]\n";              # pintamos lo encontrado
  25.  
  26.     next if $9 ne 'AMARILLO'  and  $9 ne 'ROJO'; # lo mismo, para el segundo registro
  27.        
  28.     print "[$6][$7][$8][$9][$10]\n";
  29. }
  30.  
  31. # NOMBRE DNI IDENTIFICADOR COLOR LOCALIDAD   NOMBRE DNI IDENTIFICADOR COLOR LOCALIDAD
  32. __DATA__
  33. RAUL GARCIA RODRIGUEZ     Z4385964      W3 436547873 0        AZUL CLARO        MIRANDA DE EBRO   RAUL GARCIA RODRIGUEZ     Z4385964      W3 436547873 0        AZUL CLARO        MIRANDA DE EBRO
  34. CARLOS SANZ           43645342      43     324543453     34     AMARILLO           SEVILLA   LUIS ANTONIO RUIZ                       33     323KJ5434    5     AMARILLO      VALENCIA
  35. LUIS ANTONIO RUIZ                       33     323KJ5434    5     AMARILLO      VALENCIA     LUIS ANTONIO RUIZ                       33     323KJ5434    5     AMARILLO      VALENCIA
  36.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

En el caso del DNI, ponemos que, primero intente localizar 9 blancos. Y que si los encuentre, no vuelva hacia atrás para intentar acomodar el resto de campos. Eso se consigue con el '?' que le sigue. De todas maneras, la conjunción de campos de separación con el resto de campos ayuda a 'encajar' el campo de DNI vacío entre el mar de blancos (DNI rodeado por separadores también blancos).

La explicación de las expresiones regulares es la siguiente:
* $sep = qr/ {3,}/; Los separadores son 3 o más espacios

* $texto = qr/((?:\w| {0,2}(?=\w))+)/; Un texto de un campo cualquiera será un conjunto de caracteres alfanuméricos y/o blancos, pero estos últimos deben estar seguidos por otro carácter alfanumérico. Se podría simplificar en qr/(\b[\w ]+\b)/, pero habría un ligero retraso por backtracking con el siguiente separador (le hemos "comido" todos sus blancos)

* $nombre = $texto;
* $color = $texto;
* $localidad = $texto; Estos tres campos contienen la misma expresión regular

* $dni = qr/( {9}?| {0,8}\w{1,9})/; Un DNI son 9 blancos; o un conjunto de entre 0 y 8 blancos seguidos por un conjunto de entre 1 y 9 alfanuméricos. Si hay 9 blancos, terminamos enseguida '?', y solo ocurre backtracking para liberar espacios para el separador que nos sigue y cogerlos del precedente

* $ident = qr/(\w\w +.{9} +\w\w?)/; Una expresión regular normal

* $registro = qr/$nombre $sep $dni $sep $ident $sep $color $sep $localidad/x; La unión de todos los demás
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


Volver a Básico

¿Quién está conectado?

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