Validar clave que sólo tenga tres dígitos con una expresión regular

publicado por: Anonymous

Tengo que crear una clave controlada por una expresión regular con una serie de características. Tiene que tener al menos:

  • una letra mayúscula,
  • una minúscula,
  • una acentuada,
  • un signo de euro, asterisco o dolar (una de ellas, no las tres)
  • 3 dígitos (ni uno mas ni uno menos) y
  • no puede acabar tampoco en dígito.

Bien, he creado para ello la siguiente expresión regular:

^(?=.*[a-zñ])(?=.*[A-ZÑ])(?=.*[áéíóúÁÉIÓÚ])(?=.*d){3}(?=.*[$€*])[a-zA-ZáéíóúÁÉÍÓÚñÑ$€*d]{7,15}(D$)

El asunto es que cumple todos los requisitos salvo el de los tres dígitos, pudiendo introducir más de tres (ya sean seguidos o salteados), y ya no se me escapa, consideraba tenerlo controlado con la expresión: (?=.*d){3}.

solución

Entre las condiciones que listaste, si tu expresión es correcta, te olvidaste mencionar:

  • No puede tener ninguna otra letra o símbolo que no sea los que listaste
    (no están permitidos: ü, ., @, ç, etc).
  • Debe tener entre 8 y 16 caracteres.

Cómo exigir los dígitos

Para poner la condición de que tenga 3, y no más que 3, dígitos en una inspección positiva (positive lookahead), veo que intentaste con:

/^(?=.*d){3}/

Repetir una inspección, si bien es sintácticamente correcto, no tiene sentido. Internamente, el motor de expresiones regulares, al terminar de verificar una inspección, vuelve al lugar donde se encontraba en el string antes de intentar la coincidencia. Por ejemplo, en este caso, volvería al inicio del string. Es decir, sería como validar que:

  1. Exista 1 dígito luego del inicio del string, y
  2. tenga 1 dígito después del inicio, y
  3. haya 1 dígito después del comienzo del string.

Claramente, se verifica lo mismo 3 veces. Y sería lo mismo que la expresión regular
/^(?=.*d)(?=.*d)(?=.*d)/ (redundante).

En cambio, la repetición debe estar dentro de la inspección. Por ejemplo, con esto nos garantizaríamos que la línea tenga al menos 3 dígitos:

/^(?=.*d.*d.*d)/

que podemos simplificar usando un grupo (o paréntesis no capturador):

/^(?=(?:.*d){3})/

Pero también agregaste la condición de que no tenga más de 3 dígitos. Para tal fin, tenemos que recorrer todo el string, evaluando que no haya dígitos entre estas repeticiones, y hasta el final.

Podemos utilizar D, que coincide con un caracter que no es un dígito (es lo mismo que [^d] o [^0-9]).

/^(?=(?:D*d){3}D*$)/

Así, verificamos que, desde el inicio del string, coincida con:

  1. D* – cualquier cantidad de caracteres, excepto dígitos.
  2. d – seguidos de 1 dígito.
  3. (?:){3} – Las 2 condiciones anteriores repetidas 3 veces
    (no dígitos + 1 dígito + no dígitos + 1 dígito + no dígitos + 1 dígito).
  4. D* – seguido de cualquier cantidad de caracteres que no sean dígitos.
  5. $ – seguidos del final del string.

Que no termine en dígito

Utilizando la estructura de recién, podemos verificar que exista al menos 1 D entre el último dígito y el final, evitándonos la estructura que habías utilizado ((D$), que dejaba lugar a errores). Es decir, sólo basta con cambiar el último cuantificador:

/^(?=(?:D*d){3}D+$)/

Con D+ estamos exigiendo que haya al menos 1 caracter que no sea un dígito antes del final del string (ver cuantificadores, o repetition).

Expresión regular

/^(?=.*[a-zñ])(?=.*[A-ZÑ])(?=.*[áéíóúÁÉIÓÚ])(?=(?:D*d){3}D+$)(?=.*[$€*])[da-zA-ZáéíóúÁÉÍÓÚñÑ$€*]{8,16}$/

Demo en regex101.com

Ejemplo en JavaScript

_x000D_

_x000D_

let clave   = document.getElementById('clave'),_x000D_
    valido  = document.getElementById('valido'),_x000D_
    claveok = /^(?=.*[a-zñ])(?=.*[A-ZÑ])(?=.*[áéíóúÁÉIÓÚ])(?=(?:D*d){3}D+$)(?=.*[$€*])[da-zA-ZáéíóúÁÉÍÓÚñÑ$€*]{8,16}$/;_x000D_
_x000D_
clave.addEventListener('input',function(evt){_x000D_
  if (claveok.test(clave.value)) {_x000D_
    valido.innerText = 'Ok';_x000D_
  } else {_x000D_
    valido.innerText = 'Inválido';_x000D_
  }_x000D_
});

_x000D_

<input type="text" id="clave">_x000D_
<span  id="valido"></span>

_x000D_

_x000D_

_x000D_

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *