Toutes les réponses données précédemment utilisent la même technique (correcte) pour utiliser un lookahead séparé pour chaque exigence. Mais elles contiennent quelques inefficacités et un bogue potentiellement important, en fonction du back-end qui utilisera effectivement le mot de passe.
Je vais commencer par la regex de la réponse acceptée :
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
Tout d'abord, puisque Java supporte \A
y \z
Je préfère les utiliser pour m'assurer que la chaîne entière est validée, indépendamment de Pattern.MULTILINE
. Cela n'affecte pas les performances, mais évite les erreurs lors du recyclage des regex.
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
La vérification que le mot de passe ne contient pas d'espace et la vérification de sa longueur minimale peuvent être effectuées en une seule passe en utilisant le quantificateur variable "tout à la fois". {8,}
sur la sténographie \S
qui limite les caractères autorisés :
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z
Si le mot de passe fourni contient un espace, toutes les vérifications seront effectuées, mais la vérification finale échouera à cause de l'espace. Ceci peut être évité en remplaçant tous les points par \S
:
\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z
Le point ne doit être utilisé que si vous voulez vraiment autoriser n'importe quel caractère. Sinon, utilisez une classe de caractères (négation) pour limiter votre regex aux seuls caractères qui sont réellement autorisés. Bien que cela fasse peu de différence dans ce cas, ne pas utiliser le point lorsque quelque chose d'autre est plus approprié est une très bonne habitude. Je vois beaucoup trop de cas de retour en arrière catastrophique parce que le développeur était trop paresseux pour utiliser quelque chose de plus approprié que le point.
Comme il y a de fortes chances que les tests initiaux trouvent un caractère approprié dans la première moitié du mot de passe, un quantificateur paresseux peut être plus efficace :
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
Mais passons maintenant à la question vraiment importante : aucune des réponses ne mentionne le fait que la question originale semble avoir été écrite par quelqu'un qui pense en ASCII. Mais en Java, les chaînes de caractères sont Unicode. Les caractères non ASCII sont-ils autorisés dans les mots de passe ? Si c'est le cas, seuls les espaces ASCII sont-ils interdits, ou tous les espaces blancs Unicode doivent-ils être exclus ?
Par défaut \s
ne correspond qu'aux espaces blancs ASCII, donc son inverse \S
correspond à tous les caractères Unicode (avec ou sans espace) et à tous les caractères ASCII sans espace. Si les caractères Unicode sont autorisés mais que les espaces Unicode ne le sont pas, la fonction UNICODE_CHARACTER_CLASS
peut être spécifié pour que \S
exclure les espaces blancs Unicode. Si les caractères Unicode ne sont pas autorisés, alors [\x21-\x7E]
peut être utilisé à la place de \S
pour correspondre à tous les caractères ASCII qui ne sont pas un espace ou un caractère de contrôle.
Ce qui nous amène au problème potentiel suivant : voulons-nous autoriser les caractères de contrôle ? La première étape dans l'écriture d'une regex correcte est de spécifier exactement ce que vous voulez faire correspondre et ce que vous ne voulez pas. La seule réponse techniquement correcte à 100 % est que la spécification du mot de passe dans la question est ambiguë car elle ne précise pas si certaines plages de caractères comme les caractères de contrôle ou les caractères non ASCII sont autorisés ou non.
4 votes
Les règles relatives aux mots de passe sont mauvaises. Veuillez consulter Référence - Validation du mot de passe pour plus d'informations.