Bash em * 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 funcionar corretamente, $a
não deve ser definido com uma senha válida, mas não aleatória, com antecedência. Se você deseja incluir a=
e uma quebra de linha na frente, são mais três caracteres, mas permite executar a coisa repetidamente. Obviamente, você também pode substituir todas as novas linhas ;
por uma única linha que possa ser executada quantas vezes desejar.
Além disso, você deve definir LC_ALL=C
ou não variáveis de ambiente específicas do código do idioma ( LANG
e LC_CTYPE
em particular), pois os intervalos de caracteres dependem da ordem de intercalação igual à ordem ascii.
/dev/urandom
é a fonte de bytes aleatórios. !-~
é o intervalo de todos os caracteres permitidos, conforme especificado na pergunta. tr -dc
remove todos os caracteres não listados em seu próximo argumento. head
leva 15 dos caracteres restantes. grep
verifica se cada um dos tipos necessários ocorre pelo menos uma vez. Sua entrada consiste em quatro cópias do candidato; portanto, a ordem dos símbolos não importa; portanto, todas as senhas possíveis têm chance de serem selecionadas. O -q
to grep suprime a saída.
Por razões desconhecidas, em /dev/random
vez de /dev/urandom
levar idades. Parece que a entropia se esgotou muito rapidamente. Se você cd
para /dev
, você pode evitar mais alguns bytes, mas que se sente um pouco como fazer batota.
Python 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 tornar o código legível, adicionei uma nova linha e recuo após o loop, que não é necessário e que não contei.
Esta é essencialmente a mesma ideia que na versão bash. A fonte aleatória aqui é random.sample
, que não repetirá elementos. Para combater esse fato, usamos 15 cópias da lista de cartas permitidas. Dessa forma, todas as combinações ainda podem ocorrer, embora aquelas com letras repetidas ocorram com menos frequência. Mas decido considerar isso um recurso, não um bug, já que a pergunta não exigia igual probabilidade para todas as permutações, apenas a possibilidade.
Python 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)
Uma nova linha e um recuo novamente não são contados. Além de algumas sobrecargas de sintaxe específicas do Python-3, esta é a mesma solução do 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)
Eu adicionei as novas linhas para facilitar a leitura, mas não as contei.
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
Quebra de linha e recuo dentro do loop foram adicionados, mas não contados. Se quiser, você pode movê-lo novamente para uma ;
linha separada.