2010-01-26 12 views
9

Voy a configurar este ejemplo Perl fragmento para validar durante meses en una fecha:¿Cómo puedo usar una expresión regular para validar la entrada del mes?

Algunos escenarios que desea aceptar son:

MM M

#!/usr/bin/perl 
use strict; 
use warnings; 

my $pattern; 
my $month = "(0[1-9]|1[012])"; 
my $day = "(0[1-9]|[12]\d|3[01])"; 

system("cls"); 

do { 

    print "Enter in a month: "; 
    chomp($pattern = <STDIN>); 

    # We only want to print if the pattern matches 
    print "Pattern matches\n" if ($pattern =~ /$month/); 


} while ($pattern ne "Q"); 

Cuando ejecuto esto, filtra correctamente de 01-12, pero cuando cambio la expresión regular a:

$month = "(0?[1-9]|1[012])"; 

entonces la expresión regular permite a 13, 14, etc ... lo que GIV es?

+0

(0 [1-0] | 1 [012]?), No válida [] gama "1-0" en expresiones regulares. ¿error de tipografía? –

+0

Estoy de acuerdo con la respuesta de Greg Hewgill, pero la razón por la que no obtiene lo que desea es porque a su expresión regular le faltan metacaracteres para decirle a la expresión regular que coincida con el principio y el final de la cadena (es decir^y $). Tal como está, se corresponde con cualquier parte de tu cadena. – seth

Respuesta

22

Si realmente les gusta usar expresiones regulares, que necesita para poner^$ y, como

"^(0?[1-9]|1[012])$"

que no coincidirá con el 13, 14 ....

+2

coincidencia de patrón o problema de búsqueda. –

+1

Esto incluso funcionó para mí incluso en Javascript. –

+0

Tenga en cuenta que esto coincidiría tanto con '01' como con' 1'. Puede que no sea obvio para algunos de nosotros que solo copiamos y pegamos desde SO ... – DanGordon

17

No debe usar una expresión regular para validar el rango numérico. La expresión regular que desea es:

/^(\d+)$/ 

Entonces,

if ($1 >= 1 && $1 <= 12) { 
    # valid month 
} 

Esto es mucho más fácil de leer que cualquier expresión regular para validar un rango numérico.

Como un lado, Perl evalúa expresiones regulares por buscando dentro del objetivo para una expresión coincidente. Por lo tanto:

/(0[1-9]|1[012])/ 

busca un 0 seguido de 1 a 9, o un 1 seguido por 0, 1 o 2. Esto se correspondería con "202" por ejemplo, y muchos otros números. Por otro lado:

/(0?[1-9]|1[012])/ 

búsquedas para una opcional 0 1 a 9, o un 1 seguido por 0, 1 o 2. Por lo que "13" partidos aquí, ya que contiene un 1, igualando la primera mitad de la expresión regular Para hacer que sus expresiones regulares funcionan como se espera,

/^(0?[1-9]|1[012])$/ 

El ^ y $ anclaje de la búsqueda al inicio y al final de la cadena, respectivamente.

+1

'/ (0 [1-9] | 1 [012]) /' no coincidiría con "202", coincidiría con la parte 02 de "2 ** 02 **", pero eso es bastante diferente. –

+3

+1: expresiones regulares para la validación numérica simple es overkill. – dreamlax

+1

@Paul: Depende de lo que quiere decir con "coincidencia". En este caso, usar la expresión regular para * coincidir * contra '202' (es decir,' $ patrón = ~ m/$ mes/', anotando el significado del prefijo' m') devolvería un valor verdadero, y para el código dado que eso es precisamente lo que no queremos. Sin embargo, solo capturaría * la parte '02' con los parens. Entonces, si usas la coincidencia para significar la captura, entonces no, no sería así. –

4

para darle consejo - mes número "120" coincide también en su versión :-)

Cambio:

my $month = "(0[1-9]|1[012])"; 

a

my $month = /^(0[1-9]|1[012])$/; 

y luego jugar más con ella

0

aquí hay una forma

while(1){ 
    print "Enter in a month: "; 
    $pattern = <STDIN>; 
    chomp($pattern); 
    if ($pattern =~ /^(Q|q)$/){last;} 
    if ($pattern =~ /^[0-9]$/ || $pattern =~ /^[0-9][12]$/) { 
     print "Pattern matches\n"; 
    }else{ 
     print "try again\n"; 
    } 
} 

salida

$ perl perl.pl 
Enter in a month: 01 
Pattern matches 
Enter in a month: 000 
try again 
Enter in a month: 12 
Pattern matches 
Enter in a month: 00 
try again 
Enter in a month: 02 
Pattern matches 
Enter in a month: 13 
try again 
Enter in a month: 
+2

Esto no funciona correctamente, 41, 42, 51, 52, etc. todos dicen "coincidencias de patrones". – dreamlax

2

No utilice expresiones regulares.

Perl tiene la capacidad de evaluar automáticamente como un número o una cadena según el contexto. 01-09 evaluará a 1-9 en el contexto numérico. Por lo tanto, sólo tiene que comprobar un valor:

print "Enter in a month: "; 
chomp($pattern = <STDIN>); 
# We only want to print if the pattern matches 
print "Pattern matches\n" if ($pattern < 13 && $pattern > 0); 
+1

Y, después de haber comprobado el rango, puede imprimirlo con "% 02d" si necesita el cero inicial. –

-1
[^d>12|d<0] OR ^[d>12|d<0] 
+1

Quizás podría agregar una breve explicación sobre cómo/por qué funciona esta expresión regular para aclarar. – Amber

1

"^(1[012]|0?[1-9])$" sería mejor porque la expresión regular es asse ssed primero el primero. Supongamos que quiere hacer coincidir '12' y escribe "^(0?[1-9]|1[012])$", luego '1' se elegirá porque 0?[1-9] se toma primero.

0

Para probar month/year:

^(0?[1-9]|1[012])\/([2-9][0-9)]{3})$ 
Cuestiones relacionadas