Bash en * nix (109)
while ! grep -Pq [A-Z].*[a-z].*[0-9].*[\\W_]<<<$a$a$a$a
do a=`tr -dc !-~</dev/urandom|head -c15`
done
echo $a
Para que funcione correctamente, $a
no se debe establecer una contraseña válida pero no aleatoria por adelantado. Si desea incluir a=
una línea en el frente, son tres caracteres más, pero le permite ejecutar la cosa repetidamente. Obviamente, también puede reemplazar todas las líneas nuevas por ;
lo que tiene una línea que puede ejecutar con la frecuencia que desee.
Además, debería haber establecido LC_ALL=C
o no establecer variables de entorno específicas de la localidad ( LANG
y LC_CTYPE
en particular), ya que los rangos de caracteres dependen de que el orden de clasificación sea igual al orden ASCII.
/dev/urandom
es la fuente de bytes aleatorios. !-~
es el rango de todos los caracteres permitidos, como se especifica en la pregunta. tr -dc
elimina todos los caracteres que no figuran en su siguiente argumento. head
toma 15 de los personajes restantes. grep
comprueba si cada uno de los tipos requeridos ocurre al menos una vez. Su entrada consiste en cuatro copias del candidato, por lo que el orden de los símbolos no importa, por lo tanto, todas las contraseñas posibles tienen la posibilidad de ser seleccionadas. El -q
to grep suprime la salida.
Por razones desconocidas, en /dev/random
lugar de /dev/urandom
lleva años. Parece que la entropía se agotó bastante rápido. Si cd
en /dev
, puede evitar algunos más bytes, pero que se siente un poco como hacer trampa.
Pitón 2 (138)
import re,random
a=''
while not re.search('[A-Z].*[a-z].*[0-9].*[\W_]',a*4):
a=''.join(random.sample(map(chr,range(33,127))*15,15))
print a
Para que el código sea legible, agregué una nueva línea y una sangría después del ciclo que no es necesario y que no conté.
Esta es esencialmente la misma idea que en la versión bash. La fuente aleatoria aquí es random.sample
, que no repetirá elementos. Para contrarrestar este hecho, utilizamos 15 copias de la lista de letras permitidas. De esa manera, toda combinación puede ocurrir, aunque las que tienen letras repetidas ocurrirán con menos frecuencia. Pero decido considerar esto como una característica, no como un error, ya que la pregunta no requería la misma probabilidad para todas las permutaciones, solo la posibilidad.
Pitón 3 (145)
import re,random
a=''
while not re.search('[A-Z].*[a-z].*[0-9].*[\W_]',a*4):
a=''.join(random.sample(list(map(chr,range(33,127)))*15,15))
print(a)
Una nueva línea y una sangría nuevamente no cuentan. Además de algunos gastos generales de sintaxis específicos de Python-3, esta es la misma solución que para Python 2.
JavaScript (161)
a=[];for(i=33;i<127;)a.push(s=String.fromCharCode(i++));
while(!/[A-Z].*[a-z].*[0-9].*[\W_]/.test(s+s+s+s))
for(i=0,s="";i<15;++i)s+=a[Math.random()*94|0];alert(s)
Agregué las nuevas líneas para facilitar la lectura, pero no las conté.
R (114)
s<-""
while(!grepl("[A-Z].*[a-z].*[0-9].*(\\W|_)",paste(rep(s,4),collapse="")))
s<-intToUtf8(sample(33:126,15,T))
s
Salto de línea y sangría dentro del bucle agregado pero no contado. Si lo desea, puede moverlo nuevamente a una sola ;
línea separada.