Expression régulière pour vérifier si le mot de passe contient "8 caractères dont 1 lettre majuscule, 1 caractère spécial, caractères alphanumériques"


102

Je veux une expression régulière pour vérifier cela

un mot de passe doit être composé de huit caractères, dont une lettre majuscule, un caractère spécial et des caractères alphanumériques.

Et voici mon expression de validation qui est pour huit caractères dont une lettre majuscule, une lettre minuscule et un chiffre ou caractère spécial.

(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$"

Comment puis-je l'écrire pour un mot de passe qui doit comporter huit caractères, dont une lettre majuscule, un caractère spécial et des caractères alphanumériques?


26
Pourquoi avez-vous besoin d'une expression régulière pour cela? Une expression régulière complète correspondant à vos besoins sera très longue et complexe. Il est plus facile d'écrire vos contraintes en code C #.
Greg Hewgill

32
Avez-vous envisagé de vérifier un mot de passe fort, plutôt que de vérifier que le mot de passe respecte certaines règles arbitraires qui sont un proxy imparfait pour un mot de passe fort? Il existe de nombreuses bibliothèques et programmes qui, lorsqu'ils sont alimentés par un mot de passe, détermineront sa force.
Wayne Conrad

4
@GregHewgill Je voterais pour votre commentaire si je pouvais :-) Cela ressemble à un autre cas de "si tout ce que vous avez est un marteau, tout commence à ressembler à un clou".
Christian.K

3
Avez-vous besoin d' exactement un caractère majuscule / spécial ou au moins un?
mmdemirbas

4
Par exigence de l'utilisateur, voulez-vous dire que votre utilisateur dicte les détails de mise en œuvre? Peut-être devraient-ils le coder eux-mêmes, alors. Pour être honnête, je pense qu'il serait plus facile de maintenir et de comprendre si vous venez de créer des compteurs et de vérifier chaque caractère un par un, en incrémentant les compteurs appropriés pour chaque caractère qui correspond à une règle. D'un point de vue technique, ce n'est pas quelque chose qui impressionnera qui que ce soit, mais pourquoi compliquer les choses avec quelque chose qui sera sujet aux erreurs et difficile à mettre à jour?

Réponses:


132

L'expression régulière que vous recherchez sera probablement énorme et un cauchemar à maintenir, en particulier pour les personnes qui ne sont pas familières avec les expressions régulières.

Je pense qu'il serait plus facile de décomposer votre regex et de le faire un peu à la fois. Cela peut prendre un peu plus à faire, mais je suis presque sûr que sa maintenance et son débogage seraient plus faciles. Cela vous permettrait également de fournir des messages d'erreur plus dirigés à vos utilisateurs (autres que seulement Invalid Password), ce qui devrait améliorer l'expérience utilisateur.

D'après ce que je vois, vous maîtrisez assez bien les regex, donc je suppose que vous donner les expressions régulières pour faire ce dont vous avez besoin serait futile.

En voyant votre commentaire, voici comment je procéderais:

  • Doit comporter huit caractères: vous n'avez pas besoin d'une expression régulière pour cela. L'utilisation de la .Lengthpropriété devrait suffire.

  • Incluant une lettre majuscule: vous pouvez utiliser l' [A-Z]+expression régulière. Si la chaîne contient au moins une lettre majuscule, cette expression régulière produira true.

  • Un caractère spécial: vous pouvez utiliser soit le \Wqui correspondra à n'importe quel caractère qui n'est pas une lettre ou un chiffre ou bien, vous pouvez utiliser quelque chose comme ça [!@#]pour spécifier une liste personnalisée de caractères spéciaux. Notez cependant que les caractères tels que $, ^, (et )sont des caractères spéciaux dans la langue d'expression régulière, ils ont donc besoin d'être échappé comme ceci: \$. Donc, en bref, vous pouvez utiliser le \W.

  • Caractères alphanumériques: l'utilisation de \w+doit correspondre à n'importe quelle lettre, chiffre et tiret bas.

Jetez un œil à ce didacticiel pour plus d'informations.


2
je n'ai pas écrit ceci moi-même je l'obtiens de google cher ami
Rania Umair

4
@RaniaUmair: Je pense que votre commentaire prouve mon point de vue. Je vous recommande de le décomposer comme je l'ai spécifié.
npinti

35
+1 Regex est puissant, mais n'était pas destiné à résoudre un problème dans l'univers
Cristian Lupascu

@ w0lf: Je ne pourrais pas être plus d'accord. Regex est puissant, cependant, il devient trop complexe trop vite, alors mieux vaut rester simple.
npinti

pouvez-vous m'aider j'ai besoin d'un regx qui accepte au moins un nombre et au maximum 3 autres caractères peuvent être n'importe quoi
Lijo

107
(                   # Start of group
    (?=.*\d)        #   must contain at least one digit
    (?=.*[A-Z])     #   must contain at least one uppercase character
    (?=.*\W)        #   must contain at least one special symbol
       .            #     match anything with previous condition checking
         {8,8}      #        length is exactly 8 characters
)                   # End of group

En une seule ligne:

((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})

Modifier le 28/05/2019:

Vous devez faire correspondre toute la chaîne d'entrée. Ainsi, vous pouvez placer l'expression régulière entre ^et $pour éviter de supposer accidentellement des correspondances partielles comme correspondant à l'entrée entière:

^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$

Sources:


58
Parce qu'il se compose de 12 caractères
mmdemirbas

une autre condition ne doit pas commencer par un chiffre comment puis-je faire cela?
Lijo

7
Vous pouvez le raccourcir en utilisant {8} à la place pour correspondre à 8 caractères
Angelo Tricarico

sa correspondance pour $ 1eerrrrrrr .. il n'a pas de lettre majuscule.
Shilpi Jaiswal

@ShilpiJaiswal Soit vous utilisez un indicateur pour une correspondance insensible à la casse, soit vous effectuez une «recherche» au lieu de «correspondance». Pour vous assurer que vous correspondez à toute la chaîne d'entrée, vous pouvez placer l'expression régulière entre ^et $. Essayez ceci:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas

35

Tant de réponses ... toutes mauvaises!

Les expressions régulières n'ont pas d'opérateur AND, il est donc assez difficile d'écrire une regex qui correspond à des mots de passe valides, lorsque la validité est définie par quelque chose ET quelque chose d'autre ET autre chose ...

Mais, les expressions régulières n'ont un opérateur OR, donc il suffit d' appliquer le théorème de De Morgan et écrire une expression régulière qui correspond invalides des mots de passe.

tout ce qui contient moins de 8 caractères OU tout ce qui ne contient pas de chiffres OU tout ce qui ne contient pas de majuscules OU tout ce qui ne contient pas de caractères spéciaux

Alors:

^(.{0,7}|[^0-9]*|[^A-Z]*|[a-zA-Z0-9]*)$

Si quelque chose correspond à cela, c'est un mot de passe invalide .


3
Si l'OP voulait exactement 8 caractères, vous devrez donc en ajouter |.{9,}. +1 pour le concept
Daniel

Solution excellente et simple pour la question, même si je suis d'accord qu'une seule expression régulière n'est pas la meilleure pour le problème réel.
Siderite Zackwehdex

1
Les expressions régulières ne sont et les opérateurs, ils sont appelés affirmations lookahead / arrières , .
relativement_random

13

La réponse est de ne pas utiliser d'expression régulière. C'est des ensembles et du comptage.

Les expressions régulières concernent l'ordre.

Dans votre vie de programmeur, vous serez invité à faire beaucoup de choses qui n'ont pas de sens. Apprenez à creuser un niveau plus profond. Apprenez quand la question est erronée.

La question (si elle mentionnait des expressions régulières) est fausse.

Pseudocode (basculé entre trop de langues, ces derniers temps):

if s.length < 8:
    return False
nUpper = nLower = nAlphanum = nSpecial = 0
for c in s:
    if isUpper(c):
        nUpper++
    if isLower(c):
        nLower++
    if isAlphanumeric(c):
        nAlphanum++
    if isSpecial(c):
        nSpecial++
return (0 < nUpper) and (0 < nAlphanum) and (0 < nSpecial)

Je parie que vous avez lu et compris le code ci-dessus presque instantanément. Je parie que vous avez pris beaucoup plus de temps avec la regex et que vous êtes moins certain qu'elle est correcte. L'extension de l'expression régulière est risquée. Étendu l'immédiat ci-dessus, beaucoup moins.

Notez également que la question est formulée de manière imprécise. Le jeu de caractères est-il ASCII ou Unicode, ou ?? D'après ma lecture de la question, je suppose qu'au moins un caractère minuscule est supposé. Je pense donc que la dernière règle supposée devrait être:

return (0 < nUpper) and (0 < nLower) and (0 < nAlphanum) and (0 < nSpecial)

(Changer les chapeaux en axés sur la sécurité, c'est une règle vraiment ennuyeuse / inutile.)

Apprendre à savoir quand la question est erronée est beaucoup plus important que des réponses intelligentes. Une réponse intelligente à la mauvaise question est presque toujours erronée.


2
Je suis d'accord. Plus vous travaillez avec de personnes, plus le code doit être lisible, bien que certaines implémentations de regexp que j'ai vues comme réponses soient assez claires
Nicola Peluchetti

J'aime que certains utilisateurs comme vous aient le courage de dire que Regex n'est pas toujours la meilleure solution à appliquer et que parfois, une programmation simple est plus lisible.
schlebe

12

À titre d'exemple, comment cela pourrait être fait avec une regex lisible / maintenable.

Pour une expression régulière plus longue, vous devez toujours utiliser RegexOptions.IgnorePatternWhitespacepour autoriser les espaces et les commentaires dans l'expression pour une meilleure lisibilité.

String[] passwords = { "foobar", "Foobar", "Foobar1", "Fooobar12" };

foreach (String s in passwords) {

    Match password = Regex.Match(s, @"
                                      ^              # Match the start of the string
                                       (?=.*\p{Lu})  # Positive lookahead assertion, is true when there is an uppercase letter
                                       (?=.*\P{L})   # Positive lookahead assertion, is true when there is a non-letter
                                       \S{8,}        # At least 8 non whitespace characters
                                      $              # Match the end of the string
                                     ", RegexOptions.IgnorePatternWhitespace);

    if (password.Success) {
        Console.WriteLine(s + ": valid");
    }
    else {
        Console.WriteLine(s + ": invalid");
    }
}

Console.ReadLine();

C'est la meilleure façon d'abuser de la lookahead assertionsorte de modèle «et» pour couvrir toute la contrainte dans une seule expression régulière. Fonctionne pour plus de contraintes et peut facilement être généré si certaines contraintes doivent être activées / désactivées par la configuration.
dognose le

2
L'utilisation des catégories Unicode est une excellente idée. Le monde est plus large que l'ASCII!
Walter Tross

1

Si vous n'avez besoin que d'une majuscule et d'un caractère spécial, cela devrait fonctionner:

@"^(?=.{8,}$)(?=[^A-Z]*[A-Z][^A-Z]*$)\w*\W\w*$"

La chaîne AAaaaaaaa#n'est pas OK selon cette expression
Cristian Lupascu

3
Eh bien, il fait 10, pas 8 caractères et contient plus d'une majuscule, il devrait donc échouer ...
user1096188

4
Vous avez raison, il ne dit cela dans la question. Je pensais que ces règles ressemblaient plus à "au moins une majuscule" plutôt qu'à "exactement une majuscule" . Je ne suis pas sûr que ce soit ce que voulait l'OP.
Cristian Lupascu


0

Cette question commence à être virale et de nombreuses suggestions intéressantes sont apparues.

Oui, écrire à la main est difficile. Une solution plus simple consiste donc à utiliser un modèle. Bien que l'expression régulière résultante ne soit pas la plus optimale, elle sera plus facile à maintenir et / ou à modifier, et l'utilisateur aura un meilleur contrôle sur le résultat. Il est possible que j'aie manqué quelque chose, donc toute critique constructive sera utile.

Ces liens pourraient être intéressants: faire correspondre au moins 2 chiffres 2 lettres dans n'importe quel ordre dans une chaîne , langage d'expression régulière , capture de groupes

J'utilise ce modèle (?=(?:.*?({type})){({count})})basé sur tous les regex que j'ai vus dans SO. L'étape suivante consiste à remplacer le modèle nécessaire ( number, special character...) et à ajouter une configuration pour la longueur.

J'ai fait un petit cours pour composer le regex PasswordRegexGenerator.cs Un exemple:

string result = new PasswordRegexGenerator ( )
        .UpperCase ( 3, -1 )    // ... {3,}
        .Number ( 2, 4 )        // ... {2,4}
        .SpecialCharacter ( 2 ) // ... {2}
        .Total ( 8,-1 )
        .Compose ( );

/// <summary>
/// Generator for regular expression, validating password requirements.
/// </summary>
public class PasswordRegexGenerator
{
    private string _elementTemplate = "(?=(?:.*?({type})){({count})})";

    private Dictionary<string, string> _elements = new Dictionary<string, string> {
        { "uppercase", "[A-Z]" },
        { "lowercase", "[a-z]" },
        { "number", @"\d" },
        { "special", @"\W" },
        { "alphanumeric", @"\w" }
    };

    private StringBuilder _sb = new StringBuilder ( );

    private string Construct ( string what, int min, int max )
    {
        StringBuilder sb = new StringBuilder ( _elementTemplate );
        string count = min.ToString ( );

        if ( max == -1 )
        {
            count += ",";
        }
        else if ( max > 0 )
        {
            count += "," + max.ToString();
        }

        return sb
            .Replace ( "({type})", what )
            .Replace ( "({count})", count )
            .ToString ( );
    }

    /// <summary>
    /// Change the template for the generation of the regex parts
    /// </summary>
    /// <param name="newTemplate">the new template</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexTemplate ( string newTemplate )
    {
        _elementTemplate = newTemplate;
        return this;
       }

    /// <summary>
    /// Change or update the regex for a certain type ( number, uppercase ... )
    /// </summary>
    /// <param name="name">type of the regex</param>
    /// <param name="regex">new value for the regex</param>
    /// <returns></returns>
    public PasswordRegexGenerator ChangeRegexElements ( string name, string regex )
    {
        if ( _elements.ContainsKey ( name ) )
        {
            _elements[ name ] = regex;
        }
        else
        {
            _elements.Add ( name, regex );
        }
        return this;
    }

    #region construction methods 

    /// <summary>
    /// Adding number requirement
    /// </summary>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public PasswordRegexGenerator Number ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "number" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator UpperCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "uppercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator LowerCase ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "lowercase" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator SpecialCharacter ( int min = 1, int max = 0 )
    {
        _sb.Append ( Construct ( _elements[ "special" ], min, max ) );
        return this;
    }

    public PasswordRegexGenerator Total ( int min, int max = 0 )
    {
        string count = min.ToString ( ) + ( ( max == 0 ) ? "" : "," + max.ToString ( ) );
        _sb.Append ( ".{" + count + "}" );
        return this;
    }

    #endregion

    public string Compose ()
    {
        return "(" + _sb.ToString ( ) + ")";
    }
}

0

Vous pouvez utiliser la classe ci-dessous pour la validation:

public class PasswordValidator{

  private Pattern pattern;
  private Matcher matcher;

  private static final String PASSWORD_PATTERN =
          "((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%]).{6,20})";

  public PasswordValidator(){
      pattern = Pattern.compile(PASSWORD_PATTERN);
  }

  /**
   * Validate password with regular expression
   * @param password password for validation
   * @return true valid password, false invalid password
   */
  public boolean validate(final String password){

      matcher = pattern.matcher(password);
      return matcher.matches();

  }
}

où 6 et 20 sont la longueur minimale et maximale du mot de passe.


0
  • Utilisez une expression sans retour en arrière pour faire correspondre d'abord le mot de passe entier, s'il comporte au moins 8 caractères (de cette façon, il n'y a pas d'explosion combinatoire pour les mots de passe longs, mais invalides): (?>{8,})
  • Utilisez les assertions lookbehind pour vérifier la présence de tous les caractères requis (conditions ET). (?<=...)
  • Au moins un caractère majuscule: (?<=\p{Lu}.*)
  • Au moins un caractère spécial (un peu ambigu, mais utilisons pas-mot): (?<=\W.*)
  • Au moins un caractère alphanumérique (: (?<=\w.*)

Résumé:

(?>.{8,})(?<=\p{Lu}.*)(?<=\W.*)(?<=\w.*)


0

Le mieux est de ne pas utiliser de regex pour tout. Ces exigences sont très légères. Sur les opérations de chaîne par processeur, pour vérifier les critères / la validation, c'est beaucoup moins cher et plus rapide que regex!


-2
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/

15
Je vous suggère de modifier votre question et d'inclure quelques explications. Les réponses code uniquement sont parfois assez bonnes, mais les réponses code + explication sont toujours meilleures
Barranka
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.