2010-01-26 3 views
9

J'installe cet exemple Perl extrait pour valider pendant des mois dans une date:Comment puis-je utiliser une expression régulière pour valider la saisie du mois?

Certains scénarios que je veux accepter sont:

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"); 

Quand je lance cela, il filtres correctement 01-12 mais quand je change la regex:

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

alors l'expression rationnelle permet 13, 14, etc ... ce GIV es?

+0

(0 [1-0] | 1 [012]?), Plage non valide [] "1-0" dans regex. faute de frappe? –

+0

Je suis d'accord avec la réponse de Greg Hewgill mais la raison pour laquelle vous n'obtenez pas ce que vous voulez, c'est parce que votre expression régulière manque de métacaractères pour indiquer à l'expression rationnelle de correspondre au début et à la fin de votre chaîne (c.-à-d. En l'état, il correspond à n'importe quelle partie de votre chaîne. – seth

Répondre

22

Si vous aimez vraiment utiliser regex, vous avez besoin de mettre^et $, comme

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

il ne correspond pas à 13, 14 ....

+2

problème de recherche de correspondance ou de recherche. –

+1

Cela a même fonctionné pour moi même en Javascript. –

+0

Notez que cela correspond à la fois '01' et' 1'. Peut-être pas évident pour certains d'entre nous qui copient et collent de SO ... – DanGordon

17

Vous ne devez pas utiliser une expression régulière pour effectuer une validation de plage numérique. L'expression régulière que vous voulez est:

/^(\d+)$/ 

Ensuite,

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

Ceci est beaucoup plus facile à lire que toute expression régulière pour valider une plage numérique. En outre, Perl évalue les expressions régulières par en recherchant dans la cible pour une expression correspondante. Alors:

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

recherche un 0 suivi de 1 à 9, ou un 1 suivi de 0, 1 ou 2. Cette correspondrait à « 202 », par exemple, et bien d'autres numéros. D'autre part:

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

recherche un option 0 1 à 9, ou un 1 suivi de 0, 1 ou 2. Donc « 13 » correspond ici parce qu'il contient 1, correspondant à la première moitié de l'expression rationnelle. Pour rendre vos expressions régulières fonctionnent comme prévu,

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

Le ^ et $ ancre la recherche au début et à la fin de la chaîne, respectivement.

+1

'/ (0 [1-9] | 1 [012]) /' ne correspondrait pas à "202", il correspondrait à la partie 02 de "2 ** 02 **", mais c'est très différent. –

+3

+1: Les expressions régulières pour une validation numérique simple sont excessives. – dreamlax

+1

@Paul: Cela dépend de ce que vous entendez par "match". Dans ce cas, utiliser l'expression régulière pour * match * contre '202' (ie' $ pattern = ~ m/$ mois/', en notant la signification du préfixe' m') retournera une valeur vraie, et pour le code étant donné que c'est précisément ce que nous ne voulons pas. Cependant, cela ne ferait que * capturer * la partie '02' avec les parens. Donc, si vous utilisez match pour signifier capture, alors non, ce ne serait pas. –

4

Pour vous donner hint - mois numéro "120" correspond également dans votre version :-)

Change:

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

à

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

puis jouer plus avec elle

0

voici un sens

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"; 
    } 
} 

sortie

$ 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

Cela ne fonctionne pas correctement, 41, 42, 51, 52, etc tous disent "Pattern matches". – dreamlax

2

Ne pas utiliser des expressions régulières.

Perl a la capacité d'évaluer automatiquement comme un nombre ou une chaîne en fonction du contexte. 01-09 évaluera à 1-9 dans le contexte numérique. Ainsi, vous pouvez simplement vérifier une valeur:

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

Et, après avoir vérifié la plage, vous pouvez l'imprimer avec "% 02d" si vous avez besoin du zéro initial. –

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

Peut-être pourriez-vous ajouter une courte explication sur comment/pourquoi cette expression régulière fonctionne pour la clarification. – Amber

1

"^(1[012]|0?[1-9])$" serait mieux parce que l'expression régulière est asse ssed premier un premier. Disons que vous voulez correspondre à '12' et vous écrivez "^(0?[1-9]|1[012])$", alors '1' sera choisi car 0?[1-9] est pris en premier.

0

Pour tester month/year:

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