Expresión regular para comprobar si la contraseña tiene "8 caracteres, incluida 1 letra mayúscula, 1 carácter especial, caracteres alfanuméricos"


102

Quiero una expresión regular para comprobar eso

una contraseña debe tener ocho caracteres, incluida una letra mayúscula, un carácter especial y caracteres alfanuméricos.

Y aquí está mi expresión de validación que es para ocho caracteres, incluida una letra mayúscula, una letra minúscula y un número o carácter especial.

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

¿Cómo puedo escribirlo para una contraseña que debe tener ocho caracteres, incluida una letra mayúscula, un carácter especial y caracteres alfanuméricos?


26
¿Por qué necesita una expresión regular para esto? Una expresión regular completa que coincida con sus requisitos será muy larga y compleja. Es más fácil escribir sus restricciones en código C #.
Greg Hewgill

32
¿Ha considerado verificar una contraseña segura, en lugar de verificar que la contraseña cumpla con algunas reglas arbitrarias que son un proxy imperfecto para una contraseña segura? Hay muchas bibliotecas y programas que, cuando se les da una contraseña, determinarán su fuerza.
Wayne Conrad

4
@GregHewgill Daría un voto positivo a tu comentario si pudiera :-) Este parece otro caso de "si todo lo que tienes es un martillo, todo empieza a verse como un clavo".
Christian.K

3
¿Necesita exactamente un carácter especial / en mayúscula o al menos uno?
mmdemirbas

4
Por requisito del usuario, ¿quiere decir que su usuario está dictando detalles de implementación? Quizás deberían codificar esto ellos mismos, entonces. Para ser honesto, creo que sería más fácil de mantener y entender si solo crearas contadores y verificaras cada personaje uno por uno, incrementando los contadores apropiados para cada personaje que coincida con una regla. Desde un punto de vista técnico, no es algo que impresionará a nadie, pero ¿por qué complicar las cosas con algo que será propenso a errores y difícil de actualizar?

Respuestas:


132

Lo más probable es que la expresión regular que busca sea enorme y una pesadilla de mantener, especialmente para las personas que no están tan familiarizadas con las expresiones regulares.

Creo que sería más fácil desglosar tu expresión regular y hacerlo un poco a la vez. Puede que sea necesario un poco más de trabajo, pero estoy bastante seguro de que mantenerlo y depurarlo sería más fácil. Esto también le permitiría proporcionar mensajes de error más dirigidos a sus usuarios (además de solo Invalid Password), lo que debería mejorar la experiencia del usuario.

Por lo que veo, domina las expresiones regulares con bastante fluidez, así que supongo que darle las expresiones regulares para hacer lo que necesita sería inútil.

Al ver su comentario, así es como lo haría:

  • Debe tener ocho caracteres de largo: no necesita una expresión regular para esto. Usar la .Lengthpropiedad debería ser suficiente.

  • Incluyendo una letra mayúscula: puede utilizar la [A-Z]+expresión regular. Si la cadena contiene al menos una letra mayúscula, esta expresión regular cederá true.

  • Un carácter especial: puede usar el \Wque coincidirá con cualquier carácter que no sea una letra o un número o, de lo contrario, puede usar algo así [!@#]para especificar una lista personalizada de caracteres especiales. Nota sin embargo que los caracteres tales como $, ^, (y )son caracteres especiales en el lenguaje de expresiones regulares, por lo que necesitan ser escapado de este modo: \$. En resumen, puede usar el \W.

  • Caracteres alfanuméricos: el uso de \w+debe coincidir con cualquier letra, número y guión bajo.

Eche un vistazo a este tutorial para obtener más información.


2
No he escrito esto yo mismo, lo obtengo de Google, querido amigo
Rania Umair

4
@RaniaUmair: Creo que tu comentario prueba mi punto. Te recomendaría que lo desgloses como he especificado.
npinti

35
+1 Regex es poderoso, pero no estaba destinado a resolver ningún problema en el universo
Cristian Lupascu

@ w0lf: No podría estar más de acuerdo. Regex es poderoso, sin embargo, se vuelve demasiado complejo demasiado rápido, así que es mejor que sea simple.
npinti

¿Pueden ayudarme? Necesito un regx que acepte al menos un número y un máximo de 3 otros caracteres pueden ser cualquier cosa
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 una línea:

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

Editar 2019-05-28:

Debe coincidir con la cadena de entrada completa. Por lo tanto, puede encerrar la expresión regular entre ^y $para evitar asumir accidentalmente coincidencias parciales como una entrada completa:

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

Fuentes:


58
Porque consta de 12 caracteres
mmdemirbas

una condición más no debe comenzar con un dígito, ¿cómo puedo hacer esto?
Lijo

7
Puede acortarlo usando {8} en su lugar para que coincida con 8 caracteres
Angelo Tricarico

su coincidencia con $ 1eerrrrrrr .. no tiene letra mayúscula.
Shilpi Jaiswal

@ShilpiJaiswal O estás usando una bandera para una coincidencia que no distingue entre mayúsculas y minúsculas, o estás haciendo un "buscar" en lugar de "una coincidencia". Para asegurarse de que está haciendo coincidir toda la cadena de entrada, puede encerrar la expresión regular entre ^y $. Prueba esto:^((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})$
mmdemirbas

35

Tantas respuestas ... ¡todo mal!

Las expresiones regulares no tienen un operador AND, por lo que es bastante difícil escribir una expresión regular que coincida con contraseñas válidas, cuando la validez está definida por algo Y algo más Y algo más ...

Sin embargo, las expresiones regulares hacer que un operador OR, por lo que sólo aplicar el teorema de De Morgan, y escribir una expresión regular que coincide válidos contraseñas.

cualquier cosa con menos de 8 caracteres O cualquier cosa sin números O cualquier cosa sin mayúsculas O cualquier cosa sin caracteres especiales

Entonces:

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

Si algo coincide con eso, entonces es una contraseña inválida .


3
Si el OP quería exactamente 8 caracteres, tendría que agregar |.{9,}. +1 para el concepto
Daniel

Gran y simple solución para la pregunta, aunque estoy de acuerdo en que una sola expresión regular no es la óptima para el problema real.
Siderita Zackwehdex

1
Las expresiones regulares no tienen y los operadores, se llaman de búsqueda hacia delante / búsqueda hacia atrás afirmaciones.
relativamente_random

13

La respuesta es no usar una expresión regular. Esto es conjuntos y contando.

Las expresiones regulares tienen que ver con el orden.

En tu vida como programador se te pedirá que hagas muchas cosas que no tienen sentido. Aprenda a profundizar un nivel más. Aprenda cuando la pregunta es incorrecta.

La pregunta (si menciona expresiones regulares) es incorrecta.

Pseudocódigo (últimamente ha estado cambiando entre demasiados idiomas):

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)

Apuesto a que leyó y comprendió el código anterior casi al instante. Apuesto a que tardó mucho más con la expresión regular y está menos seguro de que sea correcta. Extender la expresión regular es arriesgado. Extendido el inmediato anterior, mucho menos.

Tenga en cuenta también que la pregunta está formulada de manera imprecisa. ¿El juego de caracteres es ASCII o Unicode, o ?? Mi conjetura al leer la pregunta es que se asume al menos un carácter en minúscula. Entonces creo que la última regla asumida debería ser:

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

(Cambiar de sombrero a centrado en la seguridad, esta es una regla realmente molesta / no útil).

Aprender a saber cuándo la pregunta es incorrecta es enormemente más importante que las respuestas inteligentes. Una respuesta inteligente a una pregunta incorrecta casi siempre es incorrecta.


2
Estoy de acuerdo.
Cuantas

Me gusta que algunos usuarios como tú tengan el valor de decir que Regex no siempre es la mejor solución para aplicar y que, en ocasiones, la programación simple es más legible.
schlebe

12

Como ejemplo, cómo se podría hacer esto con una expresión regular legible / mantenible.

Para una expresión regular más larga, siempre debe usar RegexOptions.IgnorePatternWhitespacepara permitir espacios en blanco y comentarios en la expresión para una mejor legibilidad.

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

Esta es la mejor manera de abusar del lookahead assertiontipo de patrón "y" para cubrir toda la restricción dentro de una sola expresión regular. Funciona para más restricciones y se puede generar fácilmente si algunas restricciones deben habilitarse / deshabilitarse por configuración.
reconocer el

2
El uso de categorías Unicode es una excelente idea. ¡El mundo es más amplio que ASCII!
Walter Tross

1

Si solo necesita una mayúscula y un carácter especial, esto debería funcionar:

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

La cadena AAaaaaaaa#no está bien según esta expresión
Cristian Lupascu

3
Bueno, tiene 10, no 8 caracteres y contiene más de una mayúscula, por lo que debería fallar ...
user1096188

4
Tiene usted razón, que no dice esto en la pregunta. Pensé que estas reglas eran más como "al menos una mayúscula" en lugar de "exactamente una mayúscula" . Sin embargo, no estoy seguro de que eso sea lo que quería el OP.
Cristian Lupascu


0

Esta pregunta comienza a ser viral y aparecieron muchas sugerencias interesantes.

Sí, escribir a mano es complicado. Por tanto, una solución más sencilla es utilizar una plantilla. Aunque la expresión regular resultante puede no ser la más óptima, será más fácil de mantener y / o cambiar, y el usuario tendrá un mejor control sobre el resultado. Es posible que me haya perdido algo, por lo que cualquier crítica constructiva será útil.

Estos enlaces pueden ser interesantes: haga coincidir al menos 2 dígitos 2 letras en cualquier orden en una cadena , Lenguaje de expresión regular , Captura de grupos

Estoy usando esta plantilla (?=(?:.*?({type})){({count})})basada en todas las expresiones regulares que vi en SO. El siguiente paso es reemplazar el patrón necesario ( number, special character...) y agregar la configuración para la longitud.

Hice una pequeña clase para componer la expresión regular PasswordRegexGenerator.cs Un ejemplo:

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

Puede usar la siguiente clase para la validación:

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

  }
}

donde 6 y 20 son la longitud mínima y máxima de la contraseña.


0
  • Use una expresión sin retroceso para hacer coincidir la contraseña completa primero, si tiene al menos 8 caracteres (de esta manera, no hay explosión combinatoria para contraseñas largas, pero no válidas): (?>{8,})
  • Use aserciones de búsqueda hacia atrás para verificar la presencia de todos los caracteres requeridos (condiciones Y). (?<=...)
  • Al menos un carácter en mayúscula: (?<=\p{Lu}.*)
  • Al menos un carácter especial (un poco ambiguo, pero usemos no palabra): (?<=\W.*)
  • Al menos un carácter alfanumérico (: (?<=\w.*)

Resumió:

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


0

Lo mejor es no usar expresiones regulares para todo. Esos requisitos son muy ligeros. En la CPU, las operaciones de cadena para verificar los criterios / validación son mucho más baratas y rápidas que las expresiones regulares.


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

15
Te sugiero que edites tu pregunta e incluyas alguna explicación. Las respuestas de solo código a veces son lo suficientemente buenas, pero las respuestas de código + explicación siempre son mejores
Barranka
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.