Todo lo dado previamente las respuestas usan la misma técnica (correcta) para usar una búsqueda anticipada separada para cada requisito. Pero contienen un par de ineficiencias y un error potencialmente masivo, dependiendo de la parte de atrás que usará la contraseña.
Voy a empezar con la expresión regular de la respuesta aceptada:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
En primer lugar, ya que es compatible con Java \A
y \z
Yo prefiero usar los para asegurarse de que toda la cadena se valida, independientemente Pattern.MULTILINE
. Esto no afecta el rendimiento, pero evita errores cuando las expresiones regulares se reciclan.
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
Comprobación de que la contraseña no contiene espacios en blanco y comprobar su longitud mínima se puede hacer en un solo paso utilizando el todo a la vez, poniendo cuantificador variable de {8,}
en la taquigrafía \S
que limita los caracteres permitidos:
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z
Si la contraseña proporcionada contiene un espacio, se realizarán todas las comprobaciones, solo para que la verificación final falle en el espacio.Esto se puede evitar mediante la sustitución de todos los puntos con \S
:
\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z
El punto sólo debe utilizarse si realmente desea permitir que cualquier carácter. De lo contrario, use una clase de caracteres (negada) para limitar su expresión regular solo a aquellos caracteres que realmente están permitidos. Aunque hace poca diferencia en este caso, not using the dot when something else is more appropriate es un muy buen hábito. Veo demasiados casos de catastrophic backtracking porque el desarrollador era demasiado perezoso para usar algo más apropiado que el punto.
Dado que hay una buena probabilidad de las pruebas iniciales encontrarán un carácter apropiado en la primera mitad de la contraseña, un cuantificador perezoso puede ser más eficiente:
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
Pero ahora para el problema realmente importante: ninguno de las respuestas mencionan el hecho de que la pregunta original parece escrita por alguien que piensa en ASCII. Pero en Java las cadenas son Unicode. ¿Se permiten caracteres no ASCII en las contraseñas? Si lo son, solo se inhabilitan los espacios ASCII o se deben excluir todos los espacios en blanco Unicode.
De forma predeterminada, \s
solo coincide con espacios en blanco ASCII, por lo que su inversa \S
coincide con todos los caracteres Unicode (espacios en blanco o no) y todos los caracteres ASCII que no sean espacios en blanco. Si se permiten caracteres Unicode pero los espacios Unicode no lo están, se puede especificar el indicador UNICODE_CHARACTER_CLASS
para hacer que \S
excluya el espacio en blanco Unicode. Si los caracteres Unicode no están permitidos, entonces se puede usar [\x21-\x7E]
en lugar de \S
para que coincida con todos los caracteres ASCII que no sean un espacio o un carácter de control.
Lo que nos lleva al próximo problema potencial: ¿queremos permitir caracteres de control? El primer paso para escribir una expresión regular adecuada es especificar exactamente lo que quiere que coincida y lo que no. La única respuesta 100% técnicamente correcta es que la especificación de la contraseña en la pregunta es ambigua porque no indica si ciertos rangos de caracteres como los caracteres de control o los caracteres no ASCII están permitidos o no.
Normas para las contraseñas son malos. Consulte [Referencia - Validación de contraseña] (https://stackoverflow.com/questions/48345922/reference-password-validation) para obtener más información. – ctwheels