Página 1 de 1

regexp con excepciones

NotaPublicado: 2012-03-25 11:02 @501
por jrblas
La expresión regular: "[A-Z]{3}[^F]{3}" reconocerá:

AQUSOL BARNEY FREDER ...

pero no...

AQUSOF BARNFY FREFER 1REDER ...

Cómo puedo decirle que, en vez de exigir 3 repeticiones de [A-Z] y 3 repeticiones de [^F], exija 2 repeticiones de [A-Z] en las tres primeras posiciones, independientemente de la posición en la que se den, y lo mismo para las repeticiones de [^F], de forma que sean válidas:

AQUSOF 1QUSOF A1USOF AQ1SOF AQ1FOL ...

En resumen, que cuando le pido "3 repeticiones de..." entienda "3 repeticiones de... pero puedes equivocarte una vez". ¿Hay forma de meter eso en la expresión regular?

Gracias,
JR

Re: regexp con excepciones

NotaPublicado: 2012-03-25 14:23 @641
por explorer
Bienvenido a los foros de Perl en Español, jrblas.

No sé si entiendo lo que quieres hacer, pero entre la reglas de las expresiones regulares no existe el concepto de 'excepción' a la regla. Bueno, sí, pero esa excepción debe formar parte, a su vez, de una regla.

Por lo que veo, quieres que identifique palabras compuestas de tres primeras letras cualesquiera, seguida de otras tres letras en las que, necesariamente, debe haber una 'F'.

Eso se puede hacer con lo siguiente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. my @palabras = qw(
  3.     AQUSOF 1QUSOF A1USOF AQ1SOF AQ1FOL
  4.     AQUSOL BARNEY FREDER
  5.     AQUSOF BARNFY FREFER 1REDER
  6.   );
  7.  
  8. for my $palabra (@palabras) {
  9.  
  10.   print "[$palabra] : ";
  11.  
  12.   my $encontrada =
  13.     $palabra =~ m/^.{3}(.{3})$/;
  14.  
  15.   my $segunda_parte = $1;
  16.  
  17.   if ($encontrada  and  $segunda_parte =~ /F/) {
  18.     print "si\n";
  19.   }
  20.   else {
  21.     print "no\n";
  22.   }
  23. }
  24.  
  25. __END__
  26. [AQUSOF] : si
  27. [1QUSOF] : si
  28. [A1USOF] : si
  29. [AQ1SOF] : si
  30. [AQ1FOL] : si
  31. [AQUSOL] : no
  32. [BARNEY] : no
  33. [FREDER] : no
  34. [AQUSOF] : si
  35. [BARNFY] : si
  36. [FREFER] : si
  37. [1REDER] : no
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Esta es otra versión un poco más compacta. Usamos una aserción consiguiente para que compruebe que lo que sigue al primer bloque de tres letras, son otras tres, y nada más. Y luego comprobamos que en esas tres letras al menos exista una 'F':
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2.  
  3. my @palabras = qw(
  4.     AQUSOF 1QUSOF A1USOF AQ1SOF AQ1FOL
  5.     AQUSOL BARNEY FREDER
  6.     AQUSOF BARNFY FREFER 1REDER
  7.     XXXXFXX
  8.   );
  9.  
  10. for my $palabra (@palabras) {
  11.  
  12.   print "[$palabra] : ";
  13.  
  14.   my $encontrada = $palabra =~ m/^.{3}(?=.{3}$).*F{1,3}.*$/;
  15.  
  16.   if ($encontrada) {
  17.     print "si\n";
  18.   }
  19.   else {
  20.     print "no\n";
  21.   }
  22. }
  23.  
  24. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
(La palabra XXXXFXX está para verificar que, efectivamente, descarta aquellas palabras de más de 6 letras, aunque tengan una 'F'.)

No sé si es esto lo que buscas...

Más información en perldoc perlre (traducido).