Pembuat Kata Sandi Acak


40

Server domain mengharuskan semua karyawan memiliki kata sandi acak yang kuat dan sesuai dengan aturan berikut:

  • Panjangnya tepat 15 karakter.
  • Hanya karakter tipe keyboard (seperti yang ditunjukkan pada tipe kode di bawah). Mengajarkan penjualan untuk menggunakan kode ALT + NUMPAD tidak diizinkan.
  • Setidaknya 1 huruf kecil: abcdefghijklmnopqrstuvwxyz
  • Setidaknya 1 huruf besar: ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • Setidaknya 1 digit angka: 0123456789
  • Setidaknya 1 simbol: `~!@#$%^&*()_+-={}|[]\:";'<>?,./

Untuk tujuan ini, TI telah menugaskan dan akan mendistribusikan Generator Kata Sandi Acak kepada semua karyawan. Semua karyawan akan diminta untuk menggunakan Penghasil Kata Sandi Acak. Persyaratan untuk Pembuat Kata Sandi Acak adalah, di samping pembatasan kata sandi di atas:

  • Itu harus dapat menghasilkan semua permutasi dari semua karakter yang diijinkan.
  • Itu harus menampilkan kata sandi yang dihasilkan di layar.
  • Kode ini harus sekecil mungkin (dalam byte).

Silakan kirimkan solusi yang Anda usulkan dalam minggu depan.


10
Anda juga harus meminta agar semua kata sandi yang diizinkan muncul dengan probabilitas yang sama (jika tidak, saya dapat membuat daftar panjang 30 karakter dengan karakter yang diizinkan, mengocoknya, dan memberikan 15 yang pertama)
Martin Thoma

@moose, setuju. Saya telah menambahkan aturan baru.
Hand-E-Food

22
Orang-orang IT harus dipecat, atau setidaknya berpendidikan lebih baik: Jika Anda memang menghasilkan kata sandi secara acak, maka membatasi rangkaian kata sandi yang diizinkan untuk kata sandi yang memasukkan setidaknya satu karakter dari setiap kategori sebenarnya melemahkan kata sandi, karena hal itu mengurangi ukuran kata sandi. set yang diizinkan. Dan program kami akan jauh lebih mudah jika kami tidak perlu memeriksa itu ... OK, jangan memodifikasi kontes setelah begitu banyak pengiriman telah tiba; tidak apa-apa sebagai tantangan.
MvG


1
Anda belum benar-benar menjawab @moose dengan mengharuskan semua kata sandi dapat digenerate Mereka akan muncul dengan probabilitas yang sama.
Ethan Bolker

Jawaban:


29

Mathematica (18)

Biarkan saya sedikit curang

= 15char ASCII pwd
&(^F7yP8k:*1P<t

PS tidak aman :)


6
Dimana kodenya?
DavidC

11
Apakah itu dijamin untuk memenuhi setidaknya satu dari setiap persyaratan kelas karakter ?
Hand-E-Food

3
@ Hand-E-Food Ya, benar! Jika Anda melihat interpretasinya, Anda akan melihat: panjang kata sandi 15, huruf kecil diperlukan, huruf besar diperlukan, angka diperlukan, karakter khusus diperlukan.
ybeltukov

6
+1 Pintar, tapi licik.
DavidC

10
Saya tahu bahwa Mathematica memiliki fungsi untuk semuanya, tetapi ini ?
Konrad Borowski

13

Ruby, 74 69 byte

Contoh saja secara acak dari rentang ascii 33 - 126 sampai semua kelas karakter hadir:

$_=[*?!..?~].sample(15)*''until~/\d/&&~/[a-z]/&&~/[A-Z]/&&~/\W|_/
p$_

Ruby, 39 byte

Menggunakan penemuan pintar moose:

p"0123abcdABCD-+/<".chars.sample(15)*''

Edit untuk memuaskan massa:

Perhatikan bahwa aturan berubah setelah saya pertama kali memposting ini. Pada saat itu kedua entri sebelumnya diterapkan pada aturan. Saya juga ingin menunjukkan bahwa aturannya masih belum didefinisikan dengan baik:

(..) semua permutasi dari semua karakter yang diizinkan

"Permutasi". Tidak ada permutasi dari karakter yang diperbolehkan yang sesuai dengan aturan lainnya, karena permutasi dari set karakter yang diijinkan adalah sepanjang set karakter yang diijinkan itu sendiri (sementara password seharusnya sepanjang 15 karakter). Dan tidak ada pengulangan dalam permutasi. Namun entri pertama saya masih lebih "acak" daripada banyak jawaban baik lainnya yang telah di-upgrade-kan di sini.

Namun demikian, di sini Anda memilikinya. Mengizinkan pengulangan karakter dan garis bawah:

Ruby, 77 byte

$_=([*?!..?~]*15).sample(15)*''until~/\d/&&~/[a-z]/&&~/[A-Z]/&&~/\W|_/
puts$_

Saya juga menggunakan putsbukannya yang pini karena pmencetak string yang terlampir dalam "tanda kutip" dan beberapa karakter lolos dengan backslash.

Ruby, 70 byte

Seperti yang ditunjukkan Ventero, ~dapat dilewati di depan regex, dan printdapat menggantikannya puts$_. Tetapi dengan output yang jelek ini menyebabkan Anda mungkin juga mencetak semua kata sandi yang ditolak, meremasnya menjadi satu-liner:

puts$_=([*?!..?~]*15).sample(15)*''until/\d/&&/[a-z]/&&/[A-Z]/&&/\W|_/

Penjelasan

Seperti yang diminta. $_adalah variabel semi-magis yang berisi baris terakhir yang dibaca dari input - jadi Anda tidak selalu perlu menyimpannya, seperti ini . Namun di sini kita menggunakannya karena properti lain, yaitu bahwa ~operator menerapkan regex langsung ke sana, trik yang pertama kali saya pelajari dengan chron . Saya mengganti penggunaan all, tetapi seharusnya cukup mudah dimengerti jika Anda mendapatkan sisanya ( lihat dokumen ).


2
Bisakah Anda jelaskan sedikit kode Anda? Apa yang .all?{|r|~r}harus dilakukan Apa yang $_=harus dilakukan
Martin Thoma

3
Baris sampel cerdik dan semuanya, tapi saya pikir itu melanggar "Itu harus dapat menghasilkan semua permutasi dari semua karakter yang diijinkan." Tidak ada yang mengatakan bahwa kata sandi hanya boleh berisi iklan sejauh menyangkut surat. Jika z adalah karakter yang diizinkan, harus ada kemungkinan> 0 bahwa z ada dalam kata sandi.
nitro2k01

1
Apakah \Wdi Ruby termasuk garis bawah _? Di sebagian besar dialek regex saya tahu tidak. Dan jika kode Anda tidak dapat menghasilkan kata sandi di mana satu _-satunya simbol non-alfanumerik, maka itu akan melanggar satu persyaratan. Pendekatan kedua sangat jelas melanggar persyaratan itu, tapi saya kira itu tidak diungkapkan dengan benar pada waktu itu.
MvG

1
@ MVG: Anda benar. \Wtidak mengandung garis bawah di RegEx ( sumber ) yang kompatibel dengan Perl .
Martin Thoma

1
Selain itu, solusi Anda dipengaruhi oleh masalah yang sama @ose dan saya miliki dengan Python: sampletidak mengulangi elemen, jadi kata sandi dengan elemen berulang tidak dapat dihasilkan oleh kode Anda. Bisakah Anda memperbaiki dua masalah ini untuk membuat jawaban Anda sesuai dengan pertanyaan? Melihat bagaimana solusi Anda adalah yang utama, kecuali Wolfram Alpha, alangkah baiknya jika Anda bisa menyesuaikan diri dan tetap memimpin. Saya kira itu tidak terlalu sulit.
MvG

12

Java 8 - 354 329 319 275 267 karakter

Hanya untuk bersenang-senang, menggunakan lambdas dengan Java 8 - setiap output yang mungkin memiliki probabilitas yang sama ditemukan.

Ini menggunakan fakta bahwa karakter yang diizinkan memiliki kode ascii berturut-turut, dari 33 hingga 126.

class A {
    //flags for, respectively, small caps, large caps, digits, punctuation
    static int a, A, d, p;

    public static void main(String[] x) {
        String s;
        do {
            //Using special String constructor that takes an int[]
            s = new String(new java.util.Random().ints(15, 33, 127)
                                .toArray(),
                           0, 15);
            a = A = d = p = 0;
            s.chars()
                .map(c ->
                      c > 96 & c < 123 ? a = 1
                    : c > 64 & c < 90  ? A = 1
                    : c > 47 & c < 58  ? d = 1
                    : (p = 1))
                .min();
        } while (a + A + d + p < 4);
        System.out.println(s);
    }
}

Output sampel:

.*;Tm?svthiEK`3  
o.dzMgtW5|Q?ATo  
FUmVsu<4JF4eB]1

Program terkompresi:

class A{static int a,A,d,p;public static void main(String[]x){String s;do{s=new String(new java.util.Random().ints(15,33,127).toArray(),0,15);a=A=d=p=0;s.chars().map(c->c>96&c<123?a=1:c>64&c<90?A=1:c>47&c<58?d=1:(p=1)).min();}while(a+A+d+p<4);System.out.println(s);}}


Bagaimana kalau while(a+A+d+p<4)bersama dengan a|=1bukan a++? Atau gunakan bitmasks, yaitu hal-hal seperti a|=1menembus a|=8, dengan a<15kondisi loop. Ini menyimpan 13 karakter lain jika saya menghitung dengan benar.
MvG

@MvG poin bagus - melakukan sesuatu yang serupa, menghemat beberapa karakter tambahan yang saya percaya.
assylias

@ MVG Dan menggunakan new String(int[],int,int)menyimpan 40 karakter aneh lainnya!
assylias

8

Python 2.X + 3.X (229 karakter): Hasilkan dan ganti

Ide

  1. Pertama buat daftar dengan 15 simbol yang diizinkan
  2. Ganti posisi acak rdengan angka acak
  3. Ganti posisi acak s, dengan s != r, dengan huruf besar
  4. Sama untuk huruf kecil dan simbol seperti pada 2 dan 3.

Kode

from random import randint as r, shuffle as s
a=list(range(15))
p=a[:]
for i in range(15):
    a[i]=chr(r(32,126))
s(p)
a[p.pop()]=chr(r(48,57))
a[p.pop()]=chr(r(65,90))
a[p.pop()]=chr(r(97,122))
a[p.pop()]=chr(r(33,47))
print(a)

Python 2.X + 3.X (194 karakter): Hasilkan dan centang

import random
from re import search as s
p=''
while not all([s("\d",p),s("[a-z]",p),s("[A-Z]",p),s("[\W_]",p)]):
 p=str(map(chr,[random.choice(list(range(33,127))) for i in range(15)]))
print(p)
  • Terima kasih kepada MvG yang memberi tahu saya itu \udan \ltidak ada di Python regex.
  • Terima kasih kepada grc yang mengatakan kepada saya bahwa random.sampletanpa penggantian, berarti untuk mendapatkan setiap kata sandi yang dimungkinkan kami perlu pengambilan sampel dengan penggantian.

Menggunakan cacat dalam deskripsi masalah

Saat ini, deskripsi masalah tidak menuntut setiap simbol / digit muncul dengan probabilitas yang sama. Dengan solusi berikut, Anda tidak dapat membuat asumsi tentang simbol dan / atau posisi tunggal. Tetapi Anda dapat melakukannya dengan banyak hal.

Python 2.X + 3.X (62 karakter)

from random import sample
print(sample("0123abcdABCD-+/<",15))

Terima kasih kepada daniero untuk ide menggunakan sampel.


Sangat mulus menemukan kekurangannya! Saya sudah menghubungkan itu, tetapi poin bonus untuk mengidentifikasi itu. :-)
Hand-E-Food

Gen & cek Anda mirip dengan pendekatan saya. Karena penasaran: di mana ini \ldan seterusnya untuk regex python didokumentasikan? Jangan melihatnya di referensi . Python 3.3.3 saya bahkan tidak akan menerima "\u". Itu str(…)tidak bergabung dengan huruf-huruf dalam 3.3.3 atau 2.7.6. Satu saran untuk optmization: all(s("\\"+i,p)for i in "dluW").
MvG

random.samplememilih elemen tanpa penggantian, jadi tidak semua kata sandi dimungkinkan.
grc

@ MVG: Terima kasih. Saya baru saja melihat itu \udan \lhanya vim.
Martin Thoma

7

Bash on * 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

Agar berfungsi dengan benar, $atidak harus diatur ke kata sandi yang valid tetapi tidak acak di muka. Jika Anda ingin memasukkan a=dan garis memecah di depan, itu tiga karakter lagi tetapi memungkinkan Anda untuk menjalankannya berulang kali. Anda jelas dapat juga mengganti semua baris baru dengan ;sehingga Anda memiliki satu-baris yang dapat Anda jalankan sesering mungkin.

Selain itu, Anda harus menetapkan LC_ALL=Catau tidak menyetel variabel lingkungan spesifik-lokal apa pun ( LANGdan LC_CTYPEkhususnya), karena rentang karakter bergantung pada urutan kolasi yang sama dengan urutan ascii.

/dev/urandomadalah sumber byte acak. !-~adalah rentang semua karakter yang diizinkan, sebagaimana ditentukan dalam pertanyaan. tr -dcmenghapus semua karakter yang tidak tercantum dalam argumen berikutnya. headmengambil 15 dari karakter yang tersisa. grepmemeriksa apakah masing-masing jenis yang diperlukan memang terjadi setidaknya satu kali. Inputnya terdiri dari empat salinan kandidat, sehingga urutan simbol tidak menjadi masalah, karenanya semua kata sandi yang memungkinkan berpeluang terpilih. Untuk -qgrep menekan output.

Untuk alasan yang tidak diketahui, /dev/randomalih-alih /dev/urandommembutuhkan waktu lama. Sepertinya entropi cepat habis. Jika Anda cdke dalam /dev, Anda dapat menghindari beberapa byte lagi, tapi yang terasa agak seperti kecurangan.

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

Untuk membuat kode dapat dibaca, saya menambahkan baris baru dan lekukan setelah loop yang tidak perlu dan yang saya tidak hitung.

Ini pada dasarnya ide yang sama seperti di versi bash. Sumber acak di sini adalah random.sample, yang tidak akan mengulangi elemen. Untuk mengatasi fakta ini, kami menggunakan 15 salinan dari daftar surat yang diizinkan. Dengan begitu, setiap kombinasi masih dapat terjadi, meskipun yang dengan huruf berulang akan lebih jarang terjadi. Tapi saya memutuskan untuk mempertimbangkan ini sebagai fitur, bukan bug, karena pertanyaannya tidak memerlukan probabilitas yang sama untuk semua permutasi, hanya kemungkinan.

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)

Satu baris baru dan satu indentasi lagi tidak dihitung. Terlepas dari beberapa sintaksis Python-3 khusus ini adalah solusi yang sama seperti untuk 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)

Saya menambahkan baris baru untuk keterbacaan, tetapi tidak menghitungnya.

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

Linebreak dan lekukan di dalam loop ditambahkan tetapi tidak dihitung. Jika Anda menginginkannya, Anda dapat memindahkan ini lagi ke satu ;baris terpisah.


Ha! Saya baru saja akan menunjukkan bahwa Anda dapat digunakan grepldalam kode R. Kalau saja saya berpikir untuk mengulangi kata sandi tes empat kali sehingga Anda bisa melakukan semua pemeriksaan dalam satu. Dan Anda tahu, kalau saja saya memikirkan sampledan intToUtf8. Namun, Anda perlu menambahkan replace=TRUE(atau lebih tepatnya, Anda hanya perlu menambahkan ,T) ke metode sampel Anda untuk memastikan Anda mendapatkan semua kata sandi yang mungkin.
AmeliaBR

@ AmeliaBR: Anda benar, memperbaiki replace=Tkesalahan itu, terima kasih telah menunjukkan ini. Menemukan intToUtf8dengan menebak kemungkinan nama-nama dengan penyelesaian tab membutuhkan waktu cukup lama; Saya tahu fungsi semacam itu harus ada, tetapi nama yang lebih umum seperti chrdan sebagainya tidak digunakan.
MvG

@ MVG: Saya tidak mengerti mengapa kode Python Anda berakhir sama sekali. Mengapa Anda membutuhkannya *4? Saya pikir regex Anda akan cocok dengan string apa pun, yang pertama iklan satu huruf besar, lalu apa pun, kemudian satu huruf kecil, daripada apa pun ... apa yang salah saya?
Martin Thoma

@moose: Seperti yang sudah Anda perhatikan, regex saya memeriksa kategori yang diperlukan dalam urutan tertentu. Tetapi dengan mengambil gabungan dari empat salinan kandidat saat ini, saya dapat memastikan bahwa urutan tidak lagi penting: Bahkan jika kata sandi saya adalah simbol diikuti oleh angka diikuti oleh huruf kecil diikuti oleh huruf besar, maka masih akan ada kecocokan. Satu-satunya cara agar pertandingan gagal adalah jika suatu kategori hilang sama sekali. Perhatikan juga bahwa saya re.searchtidak re.match, jadi regex mungkin cocok dengan kata sandi kandidat mana pun. Apakah ini menjelaskan mengapa akhirnya akan berakhir?
MvG

Ah, saya tidak melihat bahwa Anda menggunakan re.searchbukan re.match. Itu menjelaskannya. Tapi saya masih berpikir Anda tidak perlu *4. Terima kasih atas penjelasannya (+1)
Martin Thoma

7

C # ( 123 - 139 103 - 127 karakter dipadatkan):

Menggunakan metode kerangka kerja yang memadai di System.Web.dll:

class P
{
    static void Main()
    {
        Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15, 1));
    }
}

Kompak:

class P{static void Main()
{Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15,1));}}

Contoh:

b+m2ae0K:{dz7:A

Atau, ambil nilai parameter kedua ( int numberOfNonAlphanumericCharacters) dari baris perintah:

class P
{
    static void Main(string[] a)
    {
        Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15, int.Parse(a[0])));
    }
}

3
GeneratePasswordtidak mendukung set lengkap simbol yang ditentukan dalam pertanyaan. Saya juga tidak menemukan jaminan tentang jumlah minimum kemunculan setiap kategori karakter.
MvG

2
Anda dapat memadat lebih lanjut dengan menggunakan class Pdan string[] a.
d3dave

@ MVG, itu menarik. Sepertinya tidak termasuk simbol apa pun yang biasa digunakan untuk menulis karakter beraksen dalam bahasa seperti Prancis. Mungkin langkah yang cerdas. Mengubah bahasa keyboard akan cukup untuk mengisi kata sandi Anda.
Hand-E-Food

5

R (301 322 karakter)

Koreksi lupa memeriksa digit.

a='abcdefghijklmnopqrstuvwxyz';
f=as.factor(strsplit(paste(a,toupper(a),
    sep="0123456789`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./"),"")[[1]]);
g=gsub("(.):","\\1",levels(q:q:q:q:q:q:q:q:q:q:q:q:q:q:q));
repeat{p=g[runif(1)*length(g)]; 
    if(grepl("[A-Z]",p)&&grepl("[a-z]",p)&&grepl("[0-9]",p)&&grepl("[^A-Za-z0-9]",p))break;};
print(p);

(spasi ditambahkan hanya untuk kejelasan).

Menghasilkan semua kemungkinan permutasi 15 karakter dari 94 karakter. Kemudian secara acak memilih satu sampai cocok dengan kriteria.

Keajaiban ada dalam q:qoperasi, yang menghasilkan tipe data faktor baru yaitu interaksi dari semua faktor dalam qdaftar pertama dengan semua faktor dalam daftar kedua , dengan setiap kemungkinan kombinasi dari kedua daftar tersebut dimasukkan dalam daftar " tingkat "faktor itu. Berinteraksi 15 salinan daftar karakter yang diizinkan, dan Anda mendapatkan (94 ^ 15) tingkat yang mungkin.

Tolong jangan coba ini di rumah. Kode membutuhkan beberapa detik untuk mengetahui semua permutasi tiga karakter, saya benar-benar tidak bisa membayangkan berapa lama untuk mengetahui semua permutasi 15 karakter, jika komputer Anda tidak hanya kehabisan memori di sementara itu. Ketika saya menjalankan skrip (kata sandi tiga karakter) yang sudah selesai untuk memeriksanya, kata sandi pertama yang dilontarkannya adalah "oO =", yang saya pikirkan tentang jumlah reaksi yang harus Anda lakukan terhadap kode ini.


@MvG memiliki skrip R yang jauh lebih praktis dan jauh lebih pendek, jika tidak terlalu mengagumkan: codegolf.stackexchange.com/a/17700/12413
AmeliaBR

Namun demikian, saya menyukai ide Anda. Banyak cuplikan kode-golf yang saya lihat membiarkan fitur khusus bahasa melakukan kerja keras. Dan kode Anda tentu saja melakukannya untuk R, dengan interaksi tersebut.
MvG

4

Mathematica 170

r=RandomSample;f[i_]:=(FromCharacterCode/@Range@@i);
{t,A,a,n}=f/@{{33,126},{65,90},{97,122},{48,57}};
s=Complement[t,A,a,n];
""<>r[Join[RandomChoice/@{A,a,n,s},r[t,11]],15]

Contohnya

"<]} Pg3 / e? 3 + Z ~ Oz"
"X / 8jWe @ f (_x5P: ="
"2wz2VQhtJC? * R7 ^"


4

Python 2.7 (182)

import random as r,string as s
z=r.sample
j=list(z(s.ascii_lowercase,12)+z(s.ascii_uppercase,1)+z(s.digits,1)+z('`~!@#$%^&*()_+-={}|[]\\:";\'<>?,./',1))
r.shuffle(j)
print ''.join(j)

Anda bisa mendapatkan 9 digit lebih sedikit dengan menghapus gabungan karena tidak diperlukan oleh deskripsi masalah. Lain 2 kurang dengan menghapus spasi.
Martin Thoma

@moose saya mengambil ruang yang tepat sebelum Anda berkomentar :-) Saya merasa seperti joinagak harus ada: pengguna akan diharapkan untuk memahami daftar python sintaks dari output: ['q', 'u', ...]?
Jonathon Reinhart

1
Saya berpikir tentang menghapus cetak sama sekali. Ketika ukuran dalam byte penting, mereka mungkin hidup dalam waktu kartu punch. Dengan begitu, mereka mungkin bisa membaca memori ... hanya dengan melihatnya. Atau mereka adalah "programmer sejati": xkcd.com/378
Martin Thoma

1
Jika saya membaca kode dengan benar, ini tidak memenuhi semua persyaratan permutasi , itu akan selalu memiliki 12 karakter huruf kecil, membuat kata sandi dengan lebih dari satu grup lain (seperti aA$bc1111111111) tidak mungkin.
IQAndreas

1
Dalam pembelaan Johnathon, saya pikir aturan permutasi ditambahkan 5 menit setelah jabatannya.
Hand-E-Food

4

Golfscript (60)

Karena obl. golfscript hilang dan sebagai noob saya tetap membutuhkan latihan :)

[48 10{rand}:r~+65 26r+97 26r+33 15r+11,{;32 96r+}%~]{r}$''+

Itu hanya membangun sebuah array dengan 4 diperlukan + 11 karakter acak dan mengurutkan dalam urutan acak.


+1 untuk {r}$. Itu cara yang cukup kotor untuk mengacak daftar - saya suka itu! ;-)
Ilmari Karonen

... Namun, saya tidak berpikir ini bisa menghasilkan misalnya 0Aa~~~~~~~~~~~~. :-(
Ilmari Karonen

3

JavaScript 258 240 233 225

R=Math.random;a=b=>b[b.length*R()|0];for(x=[a(l="abcdefghijklmnopqrstuvwxyz"),a(u=l.toUpperCase()),a(n="0123456789"),a(s="`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./")];15>x.length;x.push(a(l+u+n+s)));alert(x.sort(y=>.5-R()).join(""))

Menggunakan aturan di mana:

function(x){return x*x}dapat ditulis ulang sebagai function(x)x*x. Tampaknya hanya berfungsi untuk fungsi yang mengembalikan nilai.

Iterasi berikutnya, dikurangi x.sort(function().5-R())menjadix.sort(y=>.5-R())

Iterasi berikutnya, dikurangi lebih lanjut dengan notasi panah gemuk, yang sayangnya hanya berfungsi untuk Firefox 22 dan di atasnya.


Pemadatan bagus! : D
IQAndreas

2

JavaScript (269 karakter dipadatkan)

Untuk lebih jelasnya, ini adalah kode sebelum saya memadatkannya ke JS-Fiddle :

var lowerLetters = "abcdefghijklmnopqrstuvwxyz";
var upperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var numbers = "0123456789";
var symbols = "`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./";
var allCharacters = lowerLetters + upperLetters + numbers + symbols;

String.prototype.randomChar = function() {
    return this[Math.floor(this.length * Math.random())];
}

var minLength = 15;
var result = [];

// Start off by picking one random character from each group
result.push(lowerLetters.randomChar());
result.push(upperLetters.randomChar());
result.push(numbers.randomChar());
result.push(symbols.randomChar());
// Next, pick a random character from all groups until the desired length is met
while(result.length < minLength) {
    result.push(allCharacters.randomChar());
}
result.shuffle(); // Finally, shuffle the items (custom function; doesn't actually exist in JavaScript, but is very easy to add) -> http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
result.join("");

Ini dia dipadatkan menjadi 269 karakter ( JS-Fiddle ):

l="abcdefghijklmnopqrstuvwxyz";
u=l.toUpperCase();
n="0123456789";
s="`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./";
R=Math.random;

function r(t){
    return t[~~(t.length*R())]
}

for(x=[r(l),r(u),r(n),r(s)];x.length<15;x.push(r(l+u+n+s)));
x.sort(function(){return .5-R()});
alert(x.join(""));

Karena saya mengakhiri garis dengan titik koma, semua spasi putih yang dapat dilepas diabaikan untuk penghitungan karakter, tetapi ditinggalkan untuk kejelasan.
IQAndreas

Apa yang Anda maksud dengan shuffle()menjadi "fungsi khusus". Apakah ini bagian dari JavaScript atau kode yang harus Anda tulis sendiri?
Hand-E-Food

@ Hand-E-Food Maksud saya tidak dibangun ke dalam JavaScript, dan karena setiap pengembang di sini harus tahu cara mengocok array, saya merasa memasukkan fungsi dalam kode itu tidak perlu. Ini tersedia di JS-Fiddle (baris 16).
IQAndreas

1
Maksud saya adalah, itu diperhitungkan terhadap byte-count Anda. Tapi saya melihat sekarang Anda telah mengimplementasikannya dalam versi yang dipadatkan, jadi tolong abaikan saya. :-)
Hand-E-Food

2

Clojure (63):

(->> (map char (range 33 127)) (shuffle) (take 15) (apply str))

Tetapi perlu ditingkatkan untuk memastikan bahwa mengandung setidaknya 1 karakter dari setiap kategori (Atas, Bawah, Digit, Simbol).


2

Di sql-server

declare @a nvarchar(28)
set @a='abcdefghijklmnopqrstuvwxyz'
declare @b nvarchar(max)
set @b='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
declare @c nvarchar(max)
set @c='0123456789'
declare @d nvarchar(max)
set @d='~!@#$%^&*()_+-={}|[]\:";<>?,./'

select left(substring(@a,cast(rand()*10 as int),3)+substring(@b,cast(rand()*10 as int),6)+substring(@c,cast(rand()*10 as int),3)+substring(@d,cast(rand()*10 as int),5),15)

Lihat dalam aksi - 1

melihatnya dalam Aksi - 2


1
Saya mengalami kesulitan mengikuti baris terakhir, tetapi kode itu tampaknya tidak memenuhi semua persyaratan permutasi .
IQAndreas

Kode Anda tidak akan pernah menghasilkan kata sandi apa pun yang dimulai dengan ~0Aa, atau kata sandi mana bpun yang diikuti oleh a.
Heinzi

@Heinzi: ya saya setuju semua permutasi yang diperlukan r tidak diperhitungkan hanya menampilkan panjang 15..karakter dipilih secara acak dari ... z, A..Z, 0..9,! ... + :(. ..
vhadalgi

2

SAS (191)

%macro c(p);compress(p,,"&p")ne''%mend;data x;length p$15;do x=1by 1;do t=1to 15;substr(p,t,1)=byte(ranuni(7)*94+33);end;if %c(kd)and %c(kl)and %c(ku)and %c(ad)then do;put p;stop;end;end;run;

*TQP,(f=h10*)S=

Berkomentar / indentasi:

%macro c(p); /*compress removes or keeps certain classes of characters*/
  compress(p,,"&p")ne''
%mend;
data x;
length p$15;
do x=1by 1;
    do t=1to 15;
        substr(p,t,1)=byte(ranuni(7)*94+33); /*give it a 33-126, byte discards the noninteger portion rounding down*/
    end;
    if %c(kd)and %c(kl)and %c(ku)and %c(ad)then do; /*k=keep d=digit l/u=lower/upper ad=remove digits and alphas*/
        put p;
        stop;  /*met our requirement, head home*/
    end;
end;
run;

2

PowerShell: 119

Kode Gofled

for(;!($x-cmatch'.*(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!-/:-@[-`{-~]).*')){$x='';1..15|%{$x+=[char](33..126|random)}}$x

Tidak bermain golf dan Berkomentar

# Start for loop definition.
for(
    # Skip variable initialization, start definition of run condition.
    ;
    # Loop runs if $x does not meet complexity requirements.
    # Length requirement is not tested here because it is enforced by the generator later.
    # Much thanks to @VasiliSyrakis for the RegEx help.
    !($x-cmatch'.*(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!-/:-@[-`{-~]).*')
)
{
    # Reset $x in case the script block has already run.
    $x='';
    # Use ForEach-Object, via the % alias, to run a loop 15 times.
    1..15|%{
        # Append a random ASCII character from 33-126 to $x.
        # Note: Use get-random instead of random for faster performance.
        $x+=[char](33..126|random)
    }
}
# Display $x.
$x
# Variable cleanup - not included in golfed code.
rv x

Saya pikir regex ini mungkin membuatnya sedikit lebih pendek:, ^.*(?=.{15,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!#$%&? "]).*$Anda dapat melakukan satu pertandingan dengan ini, yang hanya akan cocok ketika ada satu Atas, Bawah, Digit, Simbol.
Vasili Syrakis

@VasiliSyrakis Ok, Anda mungkin harus menuntun saya sedikit. Jangan sungkan untuk memulai ruang obrolan jika menurut Anda butuh beberapa saat. Beberapa hal yang saya bingung: 1.) Saya melihat nomor 15 termasuk di sana. Apakah itu untuk memastikan string persis 15 karakter? Jika demikian, ini dapat dihilangkan, karena skrip secara alami hanya menghasilkan string 15 karakter. 2.) Apa maksud Anda "hanya akan cocok ketika ada satu Atas, Bawah, Digit, Simbol"? Apakah itu berarti itu hanya akan cocok ketika masing-masing tepat ada satu, atau setidaknya satu? Yang pertama akan merusak barang-barang.
Iszi

Juga, apakah RegEx Anda mengabaikan pemesanan karakter? Misalnya, jika disetel ke bawah untuk mencocokkan string 4 karakter, apakah keduanya 1aZ%dan (p3Rcocok? Saya mengalami kesulitan menemukan cara untuk melakukan itu secara online.
Iszi

Menguji RegEx baru terhadap output dari skrip saya saat ini. Tampaknya tidak cukup dapat diandalkan. Kode: $x-cmatch'^.*(?=.{15,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!#$%&? "]).*$'Pertandingan bagus : Pertandingan C>suD1?hTwbDx(z j%4O]HyeG|u[U$5 O/rGeD0$hJk=GO/gagal: 3evthX3_X^nBrR` .nA ~ uYzrR4YV-r.`u-IjZE48ntQ;HxV
Iszi

Bagaimana cara membuka ruang obrolan?
Vasili Syrakis

1

Python 2.7 (149)

from random import*
''.join(map(lambda x:chr(randint(*(x[1]or(32,126)))),sorted(map(None,sample(range(15),15),((48,57),(65,90),(97,122),(33,47))))))

Ditulis dengan cara yang lebih mudah dibaca (dan tidak dapat dieksekusi);

from random import *
''.join(                                          # Concatenate characters to string
  map(                                            # Map all characters using below lambda
    lambda x:chr(randint(*(x[1] or (32, 126)))),  # Map a single range to a random character
                                                  # within a specific range if supplied,
                                                  # otherwise the default "all" range.
    sorted(                                       # After distributing ranges, sort
      map(None,                                   # zip_longest alternative, distributes the
                                                  # required ranges over 4 random positions
        sample(range(15), 15),                    # 0-14 in random order
        ((48, 57), (65, 90), (97, 122), (33, 47)) # The 4 required ranges
      )
    )
  )
)

Cukup lurus ke depan dan secara mengejutkan tidak lebih lama dari versi "menghasilkan, coba lagi pada pertandingan gagal".


Apakah Anda yakin ini benar-benar dapat menghasilkan semua kata sandi yang memenuhi syarat, termasuk misalnya 0Aa~~~~~~~~~~~~? (Catat itu '~' == chr(126).)
Ilmari Karonen

1

PSQL (189)

Terasa seperti PSQL agak verbose ... :)

SELECT ARRAY_TO_STRING(ARRAY_AGG(CHR((TRUNC((b-a)*RANDOM()+a))::int)ORDER BY RANDOM()),'')FROM(SELECT 32 a,127 b FROM generate_series(1,11)UNION ALL VALUES(48,58),(65,91),(97,123),(33,48))a

Demo SQLfiddle .


1

PHP, 235 225

Script ini mengacak karakter di sekitar dan kemudian diperiksa melalui RegEx untuk memastikan kata sandi kuat (atau dibuat ulang).

<?php
while(!preg_match('/^(?=.*[A-Z])(?=.*[^A-Za-z])(?=.*[0-9])(?=.*[a-z]).{15}$/',$p)){ $p = substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()_+-={}|[]\:";\'<>?,./'),0,15); }
echo $p;

1
Pintar, tetapi tidak memungkinkan karakter duplikat.
Hand-E-Food

1
Alih-alih while(true) ... if (condition) breakAnda dapat menggunakanwhile (!condition)
exussum

1

Javascript (209)

r=Math.random;function t(x,y){return String.fromCharCode(Math.floor(y*r()+x))};x=[t(33,14),t(48,10),t(65,26),t(97,26)];for(i=0;i<11;i++)x.push(t(32,95));console.log(x.sort(function(){return r()-0.5}).join(''))

Semi-ungolfed;

// Return a character in the range [x,x+y)
function t(x,y) { return String.fromCharCode(Math.floor(y*Math.random()+x)) }
// Prefill required ranges
x=[ t(33,14), t(48,10), t(65,26), t(97,26)]
// Push 11 totally random (valid) characters
for(i=0; i<11; i++)
  x.push(t(32,95))
// Shuffle and output as string
console.log(x.sort(function(){return Math.random()-0.5})
             .join(''))

1

Perl, 92

Tidak sesingkat jawaban Ruby, tapi saya yakin seorang penyihir Perl dapat membuat ini lebih pendek ... Saya tidak terlalu senang dengan semua m//s pada akhirnya, tetapi tampaknya bekerja dan harus memenuhi persyaratan untuk akhirnya menghasilkan semua permutasi.

do{$_=join"",map{(map{chr}33..127)[rand 94]}0..14}while!(/[A-Z]/&/[a-z]/&/\d/&/[\W_]/);print

Penggunaan sampel:

perl -e 'do{$_=join"",map{(map{chr}33..127)[rand 94]}0..14}while!(/[A-Z]/&/[a-z]/&/\d/&/[\W_]/);print'

Diedit untuk memperbaiki validasi dan berubah [[:punct:]]menjadi [\W_]setelah komentar MvG.


1
Bagian generasi Anda baik, tetapi kriteria pilihan Anda dalam kondisi loop jelas salah: misalnya kata sandi aaaaaaaaaaaaaaakan menyebabkan loop berakhir. Anda harus menguji kriteria dengan kata sandi non-acak untuk memastikan mereka melakukan apa yang Anda inginkan.
MvG

Memang, Anda benar, saya sudah memperbaiki ini dan menyimpan beberapa byte! Terima kasih!
Dom Hastings

1
Apakah Anda yakin tentang ini [[:punct:]]? Saya kira saya lebih suka , which is shorter and of which I'm even more sure that it is correct, at least combined with your rentang '[\ W_] 33..127`.
MvG

Poin yang bagus, saya pikir saya khawatir yang \Wtidak termasuk _, namun Anda benar, itu tidak diperlukan: gist.github.com/anonymous/8301237 . Terima kasih!
Dom Hastings

1

Java 7 ( 270 234 karakter)

Premisnya sama dengan yang digunakan oleh @assylias dengan java 8 (menghasilkan kata sandi acak hingga kata sandi yang valid). Namun, alih-alih menggunakan lambdas, kata sandi dihasilkan oleh iterasi array char dan divalidasi dengan mencocokkan regex.

class A {
  public static void main(String [] a) {
    byte[] b = new byte[15];
    String s;
    do {
      new java.util.Random().nextBytes(b);
      s = new String(b);
    } while(!s.matches("(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\\d)(?=.*?[!-/:-@\\[-`]).*"));
    System.out.println(s);
  }
}

Kode Minimum:

class A {public static void main(String[] a){byte[] b=new byte[15];String s;do{new java.util.Random().nextBytes(b);s=new String(b);}while(!s.matches("(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\\d)(?=.*?[!-/:-@\\[-`]).*"));System.out.println(s);}}

1

Powershell


Versi One Liner (143 byte)

sal g random;1..11|%{$P+=[char](33..126|g)};(65..90|g),(97..122|g),(48..57|g),(33..47+58..64+123..126|g)|%{$P=$P.insert((1..11|g),[char]$_)};$P

Versi mini (146 byte)

sal g random
1..11|%{$P+=[char](33..126|g)}
(65..90|g),(97..122|g),(48..57|g),(33..47+58..64+123..126|g)|%{$P=$P.insert((1..11|g),[char]$_)}
$P

Versi yang dapat dibaca (860 byte)

function pwgen {

    # Fulfill Upper,Lower,Digit,Symbol requirement by predefining ASCII ranges for each
    # These will be added into the string beginning at line 24

    [array[]]$symbolrange = (33..47),(58..64),(123..126)

    [char]$upper = (get-random (65..90))
    [char]$lower = (get-random (97..122))
    [char]$digit = (get-random (48..57))
    [char]$symbol = $symbolrange | get-random

    [char[]]$requirement = $upper + $lower + $digit + $symbol

    # Create the first 11 characters using any ASCII character between 32 - 126

    foreach ($number in (1..11)) {
        [string]$pass += [char](get-random (33..126))
    }

    # Insert each requirement character at a random position in the string

    foreach ($char in $requirement) {
        [string]$pass = $pass.insert((Get-Random (1..11)),$char)
    }

    return $pass
}

Kredit ke Iszi untuk berbagai tips untuk mempersingkat kode.


1
Ini tidak mencakup semua permutasi. Sebagai contoh, abcd1234ABCD{|}~tidak akan pernah muncul karena $symbolmemaksa setidaknya salah satu simbol berada di antara ASCII 33 dan 47.
Hand-E-Food

Dangit! Haruskah kamu menunjukkan kemalasanku !? Hanya bercanda ... Saya sudah mengeditnya sekarang. Saya juga membuat setiap karakter "persyaratan" pergi ke indeks terpisah dalam string, alih-alih menggumpal keempatnya bersama-sama pada indeks yang sama. Kalau saja aku bisa mempersingkat ini ...
Vasili Syrakis

Apakah ada alasan Anda tidak bisa mencukur beberapa karakter dengan menyingkat $SRmenjadi, mungkin $Q?
Iszi

Anda juga harus dapat memotong hal-hal seperti (g(65..90))turun ke 65..90|g'. And change the foreach` pernyataan untuk foreach-objectloop menggunakan %alias. Contoh: foreach($N in (1..11)){... }harus bisa dilakukan sebagai 1..11|%{... }. Saya cukup yakin ada optimasi lain yang mungkin, tetapi saya benar-benar memiliki implementasi yang sangat berbeda dalam pikiran bahwa saya berencana untuk mencobanya nanti.
Iszi

Tip-tip yang bagus :) Saya mempersingkatnya menjadi 213 byte jika saya mengeluarkan carriage return dan ganti dengan titik koma.
Vasili Syrakis

1

Faktor, 196 karakter

Algoritma yang sama seperti MvG dan moose. Ini bukan yang terpendek tetapi harus memenuhi semua kriteria (saat ini) dalam pertanyaan:

USING: io kernel math pcre random sequences sequences.repeating ;
[ 15 94 random-integers [ 33 + ] "" map-as dup 60 cycle
"[A-Z].*[a-z].*[0-9].*[\\W_]" findall { } = not ] [ drop ] until print

Saya mungkin salah mengartikan regex, tapi saya pikir sesuatu seperti ~{}|1234abcdABCDakan gagal regex.
Hand-E-Food

1
Tidak itu akan berhasil:"~{}|1234abcdABCD" 60 cycle "[A-Z].*[a-z].*[0-9].*[\\W_]" findall empty? not => t
Björn Lindqvist

Saya akan mengambil kata-kata Anda untuk itu. :-)
Hand-E-Food

1

C - 154 karakter

char p[16],c,f,w;main(){srand(time());while(f^15){c=p[15]=f=0;while(c^15){w=33+rand()%94;f|=w
>96&&w<123?1:w>47&&w<59?2:w>64&&w<91?4:8;p[c++]=w;}}puts(p);}

Bagaimana saya membenci srand()? Biarkan saya menghitung cara.


1

Haskell, 192

import System.Random
main=getStdGen>>= \g->(print.(take 15))$until((\x->all(any(`elem`x))[['a'..'z'],['A'..'Z'],['0'..'9'],['!'..'/']++":;<=>?@[\\]^_`{|}~"]).(take 15))tail$randomRs('"','~')g

String yang dicetak memiliki tanda kutip di sekitarnya dan lolos dari garis miring terbalik dan karakter kutipan; jika itu tidak printdapat diterima, dapat diganti dengan putStrLnuntuk 3 byte lebih. Ini versi yang lebih mudah dibaca:

import System.Random

main = do
    g <- getStdGen
    let chars = randomRs ('"', '~') g
    let password = take 15 $ until (hasChars.(take 15)) tail chars
    print password

hasChars :: String -> Bool
hasChars x = all (any (`elem` x)) $
    [ ['a'..'z']
    , ['A'..'Z']
    , ['0'..'9']
    , "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
    ]

Ini cukup mudah, hanya menciptakan infinite / daftar malas karakter ASCII acak dalam kisaran '!'untuk '~', kemudian melemparkan keluar elemen pertama sampai 15 pertama karakter memiliki setidaknya satu karakter dari masing-masing string karakter yang dibutuhkan.


1

Excel VBA, 209 byte

For i = 1 To 15
x = x + Chr(Int(90 * Rnd + 33))
Next
p = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*(_|[^\w])).+$"
With New RegExp
.Pattern = p
Set m = .Execute(x)
If m.Count = 0 Then
MsgBox "redo"
Else
MsgBox x
End If
End With

Secara acak menghasilkan 15 karakter ASCII sehingga semua kemungkinan kombinasi dimungkinkan. Kemudian gunakan pola ekspresi reguler untuk memeriksa apakah mengandung setidaknya satu dari setiap kriteria.

Jika ya maka kata sandi ditampilkan, jika tidak "redo" ditampilkan.

Kredit ke Bart Kiers untuk pola Ekspresi Reguler: https://stackoverflow.com/questions/1559751/regex-to-make-sure-that-the-string-contains-at-least-one-lower-case-char- atas


0

AutoHotkey 352

global o:={}
loop 4
o[c()]:=o(A_index-1)
loop 11
o[c()]:=o(m(r(),4))
loop 15
s.=o[A_index-1]
msgbox % s
r(){
Random,z
return z
}
m(z,r){
return mod(z,r)
}
c(){
while o[t:=m(r(),15)]!=""
j++
return t
}
o(f){
r0:=48,l0:=10,r1:=97,l1:=l2:=26,r2:=65
r := chr(r%f%+m(r(),l%f%))
if f=3
r:=Substr("``~!@#$%^&*()_+-={}|[]\:"";'<>?,./",m(r(),32)+1,1)
return r
}

Menggunakan - Cukup jalankan skrip


0

Python (121 karakter)

Manfaatkan fakta bahwa Anda dapat mengalikan daftar dengan Python [1,2,3] * 2 memberi [1,2,3,1,2,3]. Impor acak. Angka dalam daftar dikalikan dengan tiga adalah batas antara rentang dalam tabel ascii untuk karakter yang diperlukan, misalnya peta [65, 90] ke huruf besar.

print "".join([random.choice([chr(i) for i in range(z[0],z[1])]) for z in [[33,48],[48,58],[58,65],[65,90],[90,123]]* 3])

1
"Itu harus dapat menghasilkan semua permutasi dari semua karakter yang diizinkan." Saya tidak berpikir itu karena rentang selalu diterapkan dalam urutan yang sama ...?
Joachim Isaksson

Anda benar, terima kasih. Memang saya tidak melihat bahwa rentang harus diterapkan dalam urutan acak, mereka harus dikocok, saya akan mengeditnya sebentar lagi.
Pawelmhm

Ini perlu dimasukkan import randomdalam kode.
Mego

0

PHP 5.5 (230 byte)

echo preg_replace_callback('/./', function ($a)
{
  return chr([rand(33, 126), rand(48, 57), rand(65, 90), rand(97, 122), ord(str_shuffle('`~!@#$%^&*()_+-={}|[]\:";\'<>?,./')[0])][$a[0]]);
}
, str_shuffle(str_pad('1234', 15, 0)));

Atau dalam satu baris (211 byte)

echo preg_replace_callback('/./',function($a){return chr([rand(33,126),rand(48,57),rand(65,90),rand(97,122),ord(str_shuffle('`~!@#$%^&*()_+-={}|[]\:";\'<>?,./')[0])][$a[0]]);},str_shuffle(str_pad('1234',15,0)));
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.