Regex para comprobar que existen al menos 3 de 4 grupos de caracteres diferentes

Estoy intentando escribir un validador de contraseñas.

¿Cómo puedo ver si mi cadena proporcionada contiene al menos 3 grupos de caracteres diferentes?

Es bastante fácil comprobar si existen o no, pero ¿al menos 3?

  • al menos ocho (8) caracteres

  • Al menos tres grupos de personajes diferentes

    letra mayúscula

    letra minúscula

    numérico

    caracteres especiales! @ # $% & / =? _.,:; - \

(Estoy usando javascript para expresiones regulares)

preguntado el 10 de mayo de 11 a las 13:05

Por cierto, @Yonder, ¿por qué solo necesitas una expresión regular? ¿Quieres ponerlo en algunos controles de validación JS? -

6 Respuestas

Solo para aprender: ¿sería posible implementar este tipo de requisito en expresiones regulares puras?

Eso haría que sea una solución bastante difícil de leer (¡y por lo tanto mantener!), Pero aquí está:

(?mx)
^
(
  (?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])                # must contain a-z, A-Z and 0-9
  |                                                # OR
  (?=.*[a-z])(?=.*[A-Z])(?=.*[!@\#$%&/=?_.,:;\\-]) # must contain a-z, A-Z and special
  |                                                # OR
  (?=.*[a-z])(?=.*[0-9])(?=.*[!@\#$%&/=?_.,:;\\-]) # must contain a-z, 0-9 and special
  |                                                # OR
  (?=.*[A-Z])(?=.*[0-9])(?=.*[!@\#$%&/=?_.,:;\\-]) # must contain A-Z, 0-9 and special
)
.{8,}                                              # at least 8 chars
$

Una demostración de Javascript (horrible):

var pw = "aa$aa1aa";
if(pw.match(/^((?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])|(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%&\/=?_.,:;\\-])|(?=.*[a-z])(?=.*[0-9])(?=.*[!@#$%&\/=?_.,:;\\-])|(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%&\/=?_.,:;\\-])).{8,}$/)) {
  print('Okay!');
} else {
  print('Fail...');
}

huellas dactilares: Okay!, como puedes ver en Ideone.

contestado el 10 de mayo de 11 a las 18:05

Aparte, siempre he querido que las expresiones regulares tengan la capacidad de almacenar patrones. Me encuentro reutilizando patrones varias veces para que no sea una opción significativa. Básicamente, algo como (?\A[a-z]) asignar \A a [a-z]. Supongo que seguiré soñando. - Brad Christie

@Brad, eso is una buena idea. Puede construir su patrón a partir de cadenas, por supuesto, concatenarlas y hacer new RegExp(a+"@"+a), Donde a es una cadena de patrón predefinida. (pero probablemente lo sepas ...) - Bart Kiers

@BartKiers: Eso es lo que he estado haciendo, solo para facilitar el mantenimiento, pero sería bueno ver "macros de expresiones regulares". Tal vez forzar la definición al comienzo del patrón, luego permitir su uso durante la duración de ese patrón. ;-) - Brad Christie

@Brad, muchos entusiastas de las expresiones regulares agradecerían este tipo de trucos (como yo), pero, como sabrá, por cada entusiasta de las expresiones regulares, probablemente haya alrededor de 10 personas que están en contra de introducir tales atajos en un ya "difícil de leer " idioma. :) - Bart Kiers

@BartKiers: estoy de acuerdo, necesitamos traer de vuelta :labels y goto¿s? Y sabes lo que dicen sobre la resolución de un problema con expresiones regulares: ahora tienes dos problemas. :sonrisa: - Brad Christie

También puede unirse a la diversión:

String.prototype.isValidPW = function(){   
    // First, check for at least 8 characters
    if (this.length < 8) return false;

    // next, check that we have at least 3 matches
    var re = [/\d/, /[A-Z]/, /[a-z]/, /[!@#$%&\/=?_.,:;-]/], m = 0;
    for (var r = 0; r < re.length; r++){
        if ((this.match(re[r]) || []).length > 0) m++;
    }

    return m >= 3;
};

if ("P@ssW0rd".isValidPW()) alert('Acceptable!');

Demo

contestado el 10 de mayo de 11 a las 18:05

Buena esa. Tenga en cuenta que no necesita escapar del ., $ y ? dentro de una clase de personaje. - Bart Kiers

@BartKiers: Historia divertida con eso: escapé del ] por accidente y estaba recibiendo errores JS. Un poco desconcertado de que no se aceptara el patrón, escapé de todo y uno por uno eliminé las letras. Luego, un rasguño en la cabeza más tarde, lo atrapé y olvidé dejar de escapar del resto. :UPS: ;-) - Brad Christie

Lo más interesante será ponerlo no en String.proto, sino en algún otro objeto. Y también para crear esas expresiones regulares una vez, como: jsfiddle.net/XnPb4 - gaRex

Esta fue mi solución favorita, pero ninguna de las soluciones proporcionadas garantizó que todas los personajes eran del tipo aceptable. Por ejemplo, una sola comilla (') alertaría' ¡Aceptable! ' aquí. Mi solución rápida fue cambiar la devolución a: return (m >= 3 && this.match(/^[0-9a-zA-Z!@#$%&\/=?_.,:;-]+$/)); - Gremio

Supongo que usará diferentes expresiones regulares para diferentes requisitos. En ese caso, dígame si lo siguiente funciona para usted:

var e = password.match(/.{8,}/); //At least 8 chars

var a = password.match(/[0-9]+/); //numeric
var b = password.match(/[A-Z]+/); //Capitals
var c = password.match(/[a-z]+/); //small letters
var d = password.match(/[!@#\$%&/=?_.,:;-\\]+/); //special chars

if (a + b + c + d > 2 && e) {// Success}
else {// Failure}

contestado el 10 de mayo de 11 a las 17:05

Solución muy bonita y sencilla de entender. Muy legible. Gracias. - Allá

Solo para aprender: ¿sería posible implementar este tipo de requisito en expresiones regulares puras? - Allá

@Yonder: Sí y no. Puede validar que tiene un [A-Z], [a-z], [0-9], [<special>] pero no es que haya 3 de 4 (que yo sepa) sin dividirlo en funciones separadas. - Brad Christie

Por cierto, ¿es necesario escapar de los personajes cuando se coloca en una clase de personaje, es decir. ¿entre paréntesis? - Allá

@Yonder: solo los caracteres que son significativos para las expresiones regulares. por ejemplo, un período (.) significa "cualquier carácter", por lo que cuando desee un punto literal, debe usar \.. Igual por $ (Fin de la línea), / (en este caso porque es un envoltorio de patrón), ? (significa que el personaje es opcional o una bandera poco codiciosa), - dentro de una clase[]) significa rango para que pueda usarlo al final de la clase o escapar de él, etc. Brad Christie

http://jsfiddle.net/aSsR8/6/

/**
 * Function determine, wheter we have valid password
 * 
 * @param {String} value
 * @return {Boolean}
 */
function isValidPassword(value) {
    // Here we define all our params
    var validLength = 8,
        minSuccess  = 3,
        isNumeric   = + /\d+/.test(value),
        isCapitals  = + /[A-Z]+/.test(value),
        isSmall     = + /[a-z]+/.test(value),
        isSpecial   = + /[!@#$%&\/=\?_\.,:;\-]+/.test(value);

    if (value.length < validLength) { // 8 symbols. We don`t need regexp here
        return false;
    }

    if (isNumeric + isCapitals  + isSmall + isSpecial < minSuccess) {
        return false;
    }

    return true;
}


document.writeln(isValidPassword('abc'));
document.writeln(isValidPassword('abc123ABC'));
document.writeln(isValidPassword('abc123!23'));

contestado el 10 de mayo de 11 a las 18:05

desde cuando ... = + ... trabajar con un operador aritmético después de la asignación? - Brad Christie

Es una forma abreviada de escribir cast a int. Lo vi en algún lugar aquí ayer :) - gaRex

La respuesta de Crimson no funcionó para mí. Esto es lo que tengo.

var mystring = 'bLahbla\\';
var valid_char_count = 0;
var lc = mystring.match(/[a-z]+/);
var uc = mystring.match(/[A-Z]+/);
var dc = mystring.match(/[0-9]+/);
var sc = mystring.match(/[\!\@\#\$\%\&\=\?\_\.\,\:\;\-\\]/);

if( lc ){ valid_char_count++; }
if( uc ){ valid_char_count++; }
if( dc ){ valid_char_count++; }
if( sc ){ valid_char_count++; }

if( valid_char_count >= 3 ){ /* success */ }

contestado el 10 de mayo de 11 a las 17:05

Esto hará todo eso en una expresión regular.

^.*(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[\d\W])(?=.*[!@#\$%&/=?_\.,:;-\\]).*$

contestado el 10 de mayo de 11 a las 17:05

Debo agregar que IE6 no es compatible con la búsqueda anticipada - herostwist

No me saca 3 de 4. "Contraseña" y "Contraseña" son aceptables según este patrón (falta un numérico o un especial para ser válido). - Brad Christie

Este parece funcionar para mí ... Contraseña y PassWord fallan para mí, pero PassW0rd tiene éxito - Allá

De hecho, IE6 admite la búsqueda anticipada; es solo buggy, como se explica aquí. No sé si eso se ha solucionado todavía, pero estoy bastante seguro de que todavía estaba roto en IE7, al menos. La solución es hacer la verificación de longitud mínima: (?=.{8,}) - antes de los otros lookaheads, que ya estás haciendo. - Alan Moore

¿Necesita dos coincidencias de patrones. * (1 antes del look hacia adelante y 1 después de ellos)? Parece que solo necesitaría 1 '. *' Entre ^ y $. Además, esto no garantiza que tenga 3 de 4 clases. ** Tienes ** que tener un carácter en mayúscula y un carácter en minúscula; y debe tener al menos un dígito o carácter especial. Por ejemplo, 'pa $$ w0rd' no coincidiría, aunque tenga 3 clases. - Gremio

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.