Toutes les réponses précédemment données utilisent la même technique (correcte) pour utiliser une anticipation distincte pour chaque exigence. Mais ils contiennent quelques inefficacités et un bogue potentiellement massif, en fonction du back-end qui utilisera réellement le mot de passe.
Je vais commencer par l'expression régulière de la réponse acceptée:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
Tout d'abord, puisque Java prend en charge \A
et que \z
je préfère les utiliser pour m'assurer que toute la chaîne est validée, indépendamment de Pattern.MULTILINE
. Cela n'affecte pas les performances, mais évite les erreurs lorsque les expressions régulières sont recyclées.
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
Vérifier que le mot de passe ne contient pas d'espaces et vérifier sa longueur minimale peut être fait en un seul passage en utilisant le tout à la fois en mettant le quantificateur variable {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, seulement pour que la vérification finale échoue sur l'espace. Cela 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 souhaitez vraiment autoriser un caractère. Sinon, utilisez une classe de caractères (annulée) pour limiter votre expression régulière aux seuls caractères qui sont vraiment 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 bonnes 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 maintenant pour le problème vraiment important: 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 sont Unicode. Les caractères non ASCII sont-ils autorisés dans les mots de passe? Si tel est le cas, seuls les espaces ASCII sont-ils interdits ou tous les espaces Unicode doivent-ils être exclus.
Par défaut, \s
correspond uniquement aux espaces ASCII, donc son inverse \S
correspond à tous les caractères Unicode (espaces ou non) et à tous les caractères ASCII sans espaces. Si les caractères Unicode sont autorisés mais que les espaces Unicode ne le sont pas, l' UNICODE_CHARACTER_CLASS
indicateur peut être spécifié pour \S
exclure les espaces Unicode. Si les caractères Unicode ne sont pas autorisés, ils [\x21-\x7E]
peuvent être utilisés à la place de \S
pour faire 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 prochain problème potentiel: voulons-nous autoriser les personnages de contrôle? La première étape dans l'écriture d'une expression régulière appropriée 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 n'indique pas si certaines plages de caractères comme les caractères de contrôle ou les caractères non ASCII sont autorisées ou non.