GUID / UUID nasıl oluşturulur?


4178

JavaScript'te benzersiz benzersiz tanımlayıcılar oluşturmaya çalışıyorum. Tüm tarayıcılarda hangi rutinlerin mevcut olduğundan, yerleşik rasgele sayı üretecinin nasıl "rastgele" ve tohumlandığından emin değilim.

GUID / UUID en az 32 karakter olmalı ve onları geçerken sorun yaşamamak için ASCII aralığında kalmalıdır.


13
Dizge olarak temsil edildiğinde GUID'ler en az 36 ve en fazla 38 karakter uzunluğundadır ve ^ \ {? [A-zA-Z0-9] {36}? \} $ Ve dolayısıyla daima ascii şeklindedir.
AnthonyWJones

2
David Bau, davidbau.com/archives/2010/01/30/… adresinde çok daha iyi, görülebilir bir rasgele sayı üreteci sunuyor Blogs.cozi.com/tech/2010/04/generating- adresinden UUID oluşturma konusunda biraz farklı bir yaklaşım yazdım. uuids-in-javascript.html
George V. Reilly

Henüz kimsenin bundan bahsetmediği garip ama bütünlük için, npm'de çok sayıda guid jeneratörleri var .
George Mauer

Yanıtlar:


2339

RFC 4122'ye göre GUID'ler (Global Benzersiz Eşsiz Kimlikleyici) olarak da bilinen UUID'ler (Evrensel Olarak Benzersiz Tanımlayıcı), belirli benzersiz garantiler sağlamak için tasarlanmış tanımlayıcılardır.

Birkaç JS satırında RFC uyumlu bir UUID uygulamak mümkün olsa da (örneğin, bkz. @ Broofa'nın cevabı , aşağıda) birkaç yaygın tuzak vardır:

  • Geçersiz kimlik biçimi (UUID'ler " xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx" biçiminde olmalıdır; burada x, [0-9, af] M'den biridir; M , [1-5] ' ten biridir ve N , [8, 9, a veya b]' dir.
  • Düşük kaliteli bir rastgelelik kaynağı kullanımı (örneğin Math.random)

Bu nedenle, üretim ortamları için kod yazan geliştiricilerin uuid modülü gibi titiz ve bakımlı bir uygulama kullanmaları önerilir .


186
Aslında, RFC rasgele sayılardan oluşturulan UUID'lere izin verir. Bu şekilde tanımlamak için birkaç biti çevirmeniz yeterlidir. Bkz. Bölüm 4.4. Gerçekten Rastgele veya Sahte Rastgele Sayılardan UUID Oluşturma Algoritmaları: rfc-archive.org/getrfc.php?rfc=4122
Jason DeFontes

Zaten bu iş parçacığındaki her şeyi temel alarak, aşağıdaki "e7" varyantının iki katı daha hızlı, kripto açısından güçlü ve tüm büyük tarayıcılarda ve düğümlerde çalışan bir sürüm oluşturdum. Buraya eklemek çok büyük, bu yüzden 17 Mayıs 2020'de
ismimle

node-uuid şimdi uuid oldu (ikinci projeyle birleştikten sonra)
Catweazle

4113

Bir İçin RFC4122 sürüm 4 uyumlu çözüm, bu tek satırlık (imsi) çözümü ben ile gelebilir en kompakt:

function uuidv4() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

console.log(uuidv4());

Güncelleme, 2015-06-02 : UUID benzersizliğinin temelde rasgele sayı üretecine (RNG) dayandığını unutmayın. Kullanımlar, yukarıda çözelti Math.random()kısa olması için, ancak Math.random()bir değil , yüksek kaliteli rng garantilidir. Ayrıntılar için Adam Hyland'ın Math.random () ile ilgili mükemmel yazısına bakın. Daha sağlam bir çözüm için, daha kaliteli RNG API'leri kullanan uuid modülünü kullanmayı düşünün .

Güncelleme, 2015/08/26 : Bir yan not olarak, bu özü çarpışma belli bir olasılık ulaşmadan önce oluşturulabilir kaç kimlikleri nasıl belirleneceği anlatılmaktadır. Örneğin, 3.26x10 15 sürüm 4 RFC4122 UUID'ler ile milyonda 1 çarpışma şansınız vardır.

Güncelleme, 2017-06-28 : Chrome geliştiricilerinden Chrome, Firefox ve Safari'deki Math.random PRNG kalitesini tartışan iyi bir makale . tl; dr - 2015'in sonundan itibaren "oldukça iyi", ancak şifreleme kalitesi değil. Bu sorunu çözmek için, ES6, cryptoAPI ve biraz JS sihirbazını kullanan yukarıdaki çözümün güncellenmiş bir sürümü :

function uuidv4() {
  return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  );
}

console.log(uuidv4());

Güncelleme, 2020-01-06 : JS dilinin bir parçası olarak standart bir modül için çalışmalarda bir teklif varuuid


30
Çarpışmalar hakkında bir soru gönderdim stackoverflow.com/questions/6906916/…
Muxa

4
@marc - Math.random () kalitesi endişe vericidir. Ancak, neredeyse x-tarayıcıyı kesinlikle değiştiren temel uygulamanın ayrıntılı bir analizi olmadan, gerçek çarpışma olasılığını bilemeyiz. Yani basitlik için ideal bir rastgelelik kaynağı olduğunu varsayıyorum. Ancak, evet, bu, muxa'nın meselesinin vurguladığı gibi tehlikeli bir varsayım olabilir. Ayrıca, düğüm- uuid'de ( github.com/broofa/node-uuid ) Performansın acı çekmesine rağmen Math.random () üzerinde kriptografik kalitede rasgeleliği garanti eden diğer API'ları tercih ediyorum.
broofa

144
Şüphesiz @ Muxa'nın sorusunun cevabı 'hayır' mı? İstemciden gelen bir şeye güvenmek asla gerçekten güvenli değildir. Kullanıcılarınızın bir javascript konsolu getirme ve değişkenleri manuel olarak istedikleri bir şeye değiştirme olasılığına bağlıdır. Ya da istedikleri kimliği geri gönderebilirler. Ayrıca, kendi kimliğini seçen kullanıcının güvenlik açıklarına neden olup olmayacağına da bağlıdır. Her iki durumda da, bir tabloya giren rasgele bir sayı kimliği varsa, muhtemelen sunucu tarafı oluşturacaktım, böylece süreç üzerinde kontrolüm olduğunu biliyorum.
Cam Jackson

36
@DrewNoakes - UUID'ler sadece tamamen rastgele # dizeleri değildir. "4" uuid versiyonudur (4 = "rastgele"). "Y", uuid varyantının (temel olarak alan düzeni) nereye yerleştirilmesi gerektiğini belirtir. Daha fazla bilgi için ietf.org/rfc/rfc4122.txt dosyasının 4.1.1 ve 4.1.3 bölümlerine bakın .
broofa

5
neden c== 'x'yerine c === 'x'. Çünkü jshint başarısız oldu.
Fizer Khan

810

Broofa'nın cevabının ne kadar temiz olduğunu çok seviyorum , ama kötü uygulamalarınMath.random çarpışma şansını bırakması talihsiz bir durum .

Burada , ilk 13 onaltılı sayıyı zaman damgasının onaltılık bir kısmı ile dengeleyerek ve bir kez sayfa yüklemesinden bu yana mikrosaniyenin onaltılık bir kısmı ile dengelenerek bu sorunu çözen benzer bir RFC4122 sürüm 4 uyumlu çözüm bulunmaktadır. Bu şekilde, Math.randomaynı tohumda olsa bile , her iki istemcinin de sayfa yükünden (aynı zamanda yüksek performans süresi destekleniyorsa) VE tam olarak aynı milisaniyede (veya 10.000+ yıl sonra) UUID'yi aynı sayıda mikrosaniye üretmesi gerekir. aynı UUID'yi edinin:

function generateUUID() { // Public Domain/MIT
    var d = new Date().getTime();//Timestamp
    var d2 = (performance && performance.now && (performance.now()*1000)) || 0;//Time in microseconds since page-load or 0 if unsupported
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16;//random number between 0 and 16
        if(d > 0){//Use timestamp until depleted
            r = (d + r)%16 | 0;
            d = Math.floor(d/16);
        } else {//Use microseconds since page-load if supported
            r = (d2 + r)%16 | 0;
            d2 = Math.floor(d2/16);
        }
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
}

console.log(generateUUID())


İşte test etmek için bir keman.


31
Unutmayın, new Date().getTime()her milisaniyede bir güncellenmez. Bunun algoritmanızın beklenen rasgeleliğini nasıl etkilediğinden emin değilim.
devios1

84
performans . şimdi daha iyi olurdu. Date.now öğesinin aksine, döndürülen zaman damgaları performance.now()yalnızca bir milisaniye çözünürlükle sınırlı değildir. Bunun yerine, süreleri mikrosaniye hassasiyetine kadar kayan nokta sayıları olarak temsil ederler . Date.now'dan farklı olarak, performance.now () tarafından döndürülen değerler , manuel olarak ayarlanabilen veya Ağ Zaman Protokolü gibi bir yazılım tarafından çarpıtılmış olabilecek sistem saatinden bağımsız olarak her zaman sabit bir oranda artar .
daniellmb

6
@daniellmb Muhtemelen bir çoklu dolgu değil, gerçek belgeleri göstermek için MDN veya başka biriyle bağlantı kurmuş olmalısınız;)
Martin

2
Yuvarlama kullanımının ne olduğunu öğrenebilir miyim d = Math.floor(d/16);?
Praveen

2
@Praveen Bu işlem zaman damgasını bir onaltılık basamak sağa kaydırır ve geri kalanını bırakır. Amacı, az önce kullandığımız onaltılık basamaktan kurtulmak (en önemsiz olanı) ve bir sonraki yinelemeye hazırlamaktır.
Briguy37

431

Broofa'nın cevabı gerçekten kaygan, etkileyici - gerçekten akıllı, gerçekten ... rfc4122 uyumlu, biraz okunabilir ve kompakt. Müthiş!

O düzenli ifade bakıyoruz Ama, eğer o pek replace()geri aramalar toString()'ın ve Math.random()(o sadece sonucun 4 bit kullanarak ve dinlenme israf oluyor) işlev çağrıları, performans hakkında merak başlayabilir. Gerçekten de, joelpt, genel GUID hızı için RFC'yi atmaya bile karar verdi generateQuickGUID.

Ancak, hız ve RFC uyumluluğu alabilir miyiz ? Evet dedim! Okunabilirliği koruyabilir miyiz? Şey ... Pek değil, ama takip ederseniz kolay.

Ama önce, broofa, guid(kabul edilen cevap) ve rfc uyumlu olmayanlarla karşılaştırıldığında sonuçlarım generateQuickGuid:

                  Desktop   Android
           broofa: 1617ms   12869ms
               e1:  636ms    5778ms
               e2:  606ms    4754ms
               e3:  364ms    3003ms
               e4:  329ms    2015ms
               e5:  147ms    1156ms
               e6:  146ms    1035ms
               e7:  105ms     726ms
             guid:  962ms   10762ms
generateQuickGuid:  292ms    2961ms
  - Note: 500k iterations, results will vary by browser/cpu.

6. optimizasyon yinelememle, en popüler cevabı 12X'in üzerinde, 9X'in üzerinde kabul edilen cevabı ve 2-3X'in hızlı uyumlu olmayan cevabını yendim . Ve hala rfc4122 uyumluyum.

Nasıl? Tüm kaynağı http://jsfiddle.net/jcward/7hyaC/3/ ve http://jsperf.com/uuid-generator-opt/4 üzerine koydum

Bir açıklama için, broofa'nın koduyla başlayalım:

function broofa() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
}

console.log(broofa())

Bu nedenle x, yrastgele verilerle (en iyi 2 biti 10RFC spesifikasyonuna göre zorlamak hariç) herhangi bir rastgele onaltılık basamakla değiştirilir ve normal ifade -veya 4karakterleriyle eşleşmez , bu nedenle onlarla uğraşması gerekmez. Çok, çok kaygan.

Bilmeniz gereken ilk şey, düzenli çağrılar gibi işlev çağrılarının pahalı olmasıdır (her ne kadar sadece 1 kullanıyorsa da, her maç için bir tane olmak üzere 32 geri arama vardır ve 32. geri çağırmanın her birinde Math.random () ve v olarak adlandırılır. toString (16)).

Performansa giden ilk adım RegEx ve geri çağrı işlevlerini ortadan kaldırmak ve bunun yerine basit bir döngü kullanmaktır. Bu , broofa'nın yapmadığı -ve ve 4karakterleriyle uğraşmamız gerektiği anlamına gelir . Ayrıca, kaygan String şablonu mimarisini korumak için String Array dizinini kullanabileceğimizi unutmayın:

function e1() {
    var u='',i=0;
    while(i++<36) {
        var c='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'[i-1],r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);
        u+=(c=='-'||c=='4')?c:v.toString(16)
    }
    return u;
}

console.log(e1())

Temelde, aynı iç mantığı, biz kontrol hariç -veya 4ve (yerine while döngüsü kullanılmasının replace()geri aramaları) bize neredeyse 3X iyileşme alır!

Bir sonraki adım masaüstünde küçük bir adımdır, ancak mobil cihazlarda iyi bir fark yaratır. Daha az Math.random () çağrısı yapalım ve her yinelemeyi değiştiren rastgele bir arabellekle% 87'sini atmak yerine tüm bu rastgele bitleri kullanalım. Ayrıca, yardımcı olması durumunda bu şablon tanımını döngüden çıkaralım:

function e2() {
    var u='',m='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',i=0,rb=Math.random()*0xffffffff|0;
    while(i++<36) {
        var c=m[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
        u+=(c=='-'||c=='4')?c:v.toString(16);rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
    }
    return u
}

console.log(e2())

Bu, platforma bağlı olarak bizi% 10-30 tasarruf sağlıyor. Fena değil. Ancak bir sonraki büyük adım, bir optimizasyon klasiğiyle toString işlev çağrılarından tamamen kurtulur - arama tablosu. Basit bir 16 elemanlı arama tablosu, toString (16) işini çok daha kısa sürede gerçekleştirir:

function e3() {
    var h='0123456789abcdef';
    var k='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
    /* same as e4() below */
}
function e4() {
    var h=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
    var k=['x','x','x','x','x','x','x','x','-','x','x','x','x','-','4','x','x','x','-','y','x','x','x','-','x','x','x','x','x','x','x','x','x','x','x','x'];
    var u='',i=0,rb=Math.random()*0xffffffff|0;
    while(i++<36) {
        var c=k[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
        u+=(c=='-'||c=='4')?c:h[v];rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
    }
    return u
}

console.log(e4())

Bir sonraki optimizasyon başka bir klasik. Her döngü yinelemesinde yalnızca 4 bit çıktı işlediğimiz için, döngü sayısını yarıya indirelim ve her yinelemeyi 8 bit işleyelim. RFC uyumlu bit konumlarını hala ele almamız gerektiğinden bu zor, ancak çok zor değil. Daha sonra 0x00 - 0xff'yi saklamak için daha büyük bir arama tablosu (16x16 veya 256) yapmamız gerekiyor ve e5 () işlevinin dışında yalnızca bir kez oluşturuyoruz.

var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e5() {
    var k=['x','x','x','x','-','x','x','-','4','x','-','y','x','-','x','x','x','x','x','x'];
    var u='',i=0,rb=Math.random()*0xffffffff|0;
    while(i++<20) {
        var c=k[i-1],r=rb&0xff,v=c=='x'?r:(c=='y'?(r&0x3f|0x80):(r&0xf|0x40));
        u+=(c=='-')?c:lut[v];rb=i%4==0?Math.random()*0xffffffff|0:rb>>8
    }
    return u
}

console.log(e5())

Hala 256-element LUT kullanarak, bir seferde 16 bit işleyen bir e6 () denedim ve optimizasyon azalan dönüşlerini gösterdi. Daha az yineleme olmasına rağmen, iç mantık artan işleme ile karmaşıktı ve aynı şeyi masaüstünde gerçekleştirdi ve mobil cihazlarda yalnızca ~% 10 daha hızlıydı.

Uygulanacak son optimizasyon tekniği - döngüyü açın. Sabit sayıda döngü yaptığımız için, bunları teknik olarak elle yazabiliriz. Bunu bir kez yeniden atamaya devam ettiğim tek bir rastgele değişken r ile denedim ve performans tanklandı. Ancak dört değişkenin önüne rastgele veriler atandıktan sonra arama tablosunu kullanarak ve uygun RFC bitlerini uygulayarak bu sürüm hepsini sigara içiyor:

var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e7()
{
    var d0 = Math.random()*0xffffffff|0;
    var d1 = Math.random()*0xffffffff|0;
    var d2 = Math.random()*0xffffffff|0;
    var d3 = Math.random()*0xffffffff|0;
    return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+
    lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+
    lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
    lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
}

console.log(e7())

Değiştirilmiş: http://jcward.com/UUID.js -UUID.generate()

Komik olan şey, 16 bayt rasgele veri oluşturmak kolay bir parçadır. Tüm hile, RFC uyumluluğu ile String biçiminde ifade ediyor ve 16 bayt rastgele veri, bir kaydedilmemiş döngü ve arama tablosu ile en sıkı şekilde gerçekleştiriliyor.

Umarım mantığım doğrudur - bu tür sıkıcı bit işlerinde bir hata yapmak çok kolaydır. Ama çıktılar bana iyi geliyor. Umarım kod optimizasyonu ile bu deli sürüş zevk!

Tavsiyem: Temel amacım potansiyel optimizasyon stratejilerini göstermek ve öğretmekti. Diğer cevaplar, iyi UUID'ler oluşturmak için önemli olan çarpışmalar ve gerçekten rastgele sayılar gibi önemli konuları kapsar.


14
Bu kod hala birkaç hata içeriyor: Math.random()*0xFFFFFFFFsatırlar Math.random()*0x100000000tam rastgele olmaları için >>>0olmalı |0ve değerleri imzasız tutmak için kullanılmalıdır (mevcut kodla birlikte imzalanmış olsalar bile tamam olduğunu düşünüyorum). Son olarak window.crypto.getRandomValues, eğer varsa, bu günlerde kullanmak çok iyi bir fikir olurdu ve sadece kesinlikle gerekliyse Math.random'a geri dönecekti. Math.random 128 bitten daha az entropiye sahip olabilir, bu durumda bu çarpışmalara gerekenden daha savunmasız olacaktır.
Dave

Zaten bu iş parçacığı üzerinde her şeyi inşa, ben "e7" iki kat daha hızlı bir şey inşa ettik, düğüm de dahil olmak üzere tüm ortamları taşınabilir ve Math.random () kripto gücü rasgele yükseltildi. Uuid'in kripto gücüne ihtiyacı olduğunu düşünmeyebilirsiniz, ancak bunun anlamı, bir uuid'in tüm noktası olan bir çarpışma şansının daha az olmasıdır. Bir yoruma sığmayacak kadar büyük, ayrı olarak yayınladım.
Bennett Barouch

164

RFC 4122 , bölüm 4.4 (Gerçekten Rastgele veya Sahte Rastgele Sayıdan UUID Oluşturma Algoritmaları) tabanlı bazı kodlar .

function createUUID() {
    // http://www.ietf.org/rfc/rfc4122.txt
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = "-";

    var uuid = s.join("");
    return uuid;
}

4
GUID'i oluştururken dizi boyutunu dinamik olarak boyutlandırmak yerine önceden bildirmelisiniz. var s = new Array(36);
MgSam

1
Sanırım 01 için clock_seq_hi_and_reserved 6-7 bit bitleri ayarlar satırında çok küçük bir hata var. S [19] bir karakter '0' .. 'f' bir int 0x0..0xf olduğundan, (s [19] ve 0x3) | 0x8 rastgele dağıtılmayacak - daha fazla '9 ve daha az' b üretme eğilimi gösterecektir. Bu, sadece bir nedenle rastgele dağılımı önemsiyorsanız fark yaratır.
John Velonis

153
let uniqueId = Math.random().toString(36).substring(2) + Date.now().toString(36);

Kimlikler 1 milisaniyeden fazla aralıklarla üretilirse,% 100 benzersizdir.

Daha kısa aralıklarla iki kimlik oluşturulursa ve rastgele yöntemin gerçekten rastgele olduğunu varsayarsak, bu% 99.999999999999999'un global olarak benzersiz olma olasılığı olan kimlikler oluşturur (10 ^ 15'in 1'inde çarpışma)

Daha fazla basamak ekleyerek bu sayıyı artırabilirsiniz, ancak% 100 benzersiz kimlikler oluşturmak için genel bir sayaç kullanmanız gerekir.

RFC uyumluluğuna ihtiyacınız varsa, bu biçimlendirme geçerli bir sürüm 4 GUID'si olarak geçer:

let u = Date.now().toString(16) + Math.random().toString(16) + '0'.repeat(16);
let guid = [u.substr(0,8), u.substr(8,4), '4000-8' + u.substr(13,3), u.substr(16,12)].join('-');

Düzenleme: Yukarıdaki kod niyetini izler, ancak RFC harfini değil. Diğer tutarsızlıkların yanı sıra birkaç rastgele rakam kısa. (İhtiyacınız olursa daha fazla rastgele rakam ekleyin) Tersi, bunun gerçekten hızlı olması :) GUID'nizin geçerliliğini burada test edebilirsiniz


4
Bu UUID değil mi?
Marco Kerwitz

Hayır. UUID / GUID'ler 122 bit (+ altı ayrılmış bit) sayıdır. global bir karşı hizmet aracılığıyla benzersizliği garanti edebilir, ancak çoğu zaman zaman, MAC adresi ve rasgele geçiş yapar. UUID'ler rastgele değil! Burada önerdiğim UID tamamen sıkıştırılmamış. 122 bit tamsayıya sıkıştırabilir, önceden tanımlanmış 6 biti ve ekstra rastgele bitleri ekleyebilir (birkaç zamanlayıcı bitini kaldırabilirsiniz) ve mükemmel şekilde oluşturulmuş bir UUID / GUID ile sonuçlanırsınız. Bana göre bu kimliğin uzunluğuna uyumdan başka bir şey eklemiyor.
Simon Rigét

5
Sanal makinelerde benzersizlik için MAC adreslerini röle yapmak kötü bir fikir!
Simon Rigét

1
Ben böyle bir şey yapmak, ama önde gelen karakterler ve bazı tire (örneğin [slug, date, random].join("_")oluşturmak için usr_1dcn27itd_hj6onj6phr. Bu yüzden id de bir "oluşturulan" alanı olarak ikiye katlanır
Seph Reed

95

Formatında string jeneratör yöntemi gibi en hızlı GUID XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Bu, standart uyumlu GUID oluşturmaz.

Bu uygulamanın on milyon yürütmesi sadece 32.5 saniye sürüyor, bu da bir tarayıcıda gördüğüm en hızlı (döngüler / yinelemeler olmadan tek çözüm).

İşlev şu kadar basit:

/**
 * Generates a GUID string.
 * @returns {string} The generated GUID.
 * @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
 * @author Slavik Meltser.
 * @link http://slavik.meltser.info/?p=142
 */
function guid() {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return _p8() + _p8(true) + _p8(true) + _p8();
}

Performansı test etmek için şu kodu çalıştırabilirsiniz:

console.time('t'); 
for (var i = 0; i < 10000000; i++) { 
    guid(); 
};
console.timeEnd('t');

Eminim çoğunuz orada ne yaptığımı anlayacaksınız, ama belki de bir açıklamaya ihtiyaç duyacak en az bir kişi var:

Algoritma:

  • Math.random()Fonksiyonu (örneğin, bir ondalık kesir noktadan sonra 16 hane ile 0 ile 1 arasında bir sayıyı döndüren 0.4363923368509859).
  • Sonra bu sayıyı alıp taban 16 ile bir dizeye dönüştürürüz (yukarıdaki örnekten alacağız 0.6fb7687f).
    Math.random().toString(16).
  • Sonra 0.önek ( 0.6fb7687f=> 6fb7687f) kesilir ve sekiz onaltılık karakter uzunluğunda bir dize alırız .
    (Math.random().toString(16).substr(2,8).
  • Bazen, sondaki sıfırlar nedeniyle Math.random()işlev daha kısa sayı döndürür (örneğin 0.4363) (yukarıdaki örnekte aslında sayı 0.4363000000000000). Bu yüzden bu dizeye "000000000"(dokuz sıfırlı bir dize) ekliyorum ve daha sonra substr()dokuz karakteri tam olarak yapmak için işlevle kesiyorum (sağa sıfırları doldurma).
  • Tam olarak dokuz sıfır eklemenin nedeni, en kötü durum senaryosundan kaynaklanır; bu, Math.random()işlevin tam olarak 0 veya 1 (her biri için 1/10 ^ 16 olasılığı) döndüreceği durumdur . Bu yüzden ona ( "0"+"000000000"veya "1"+"000000000") dokuz sıfır eklememiz ve daha sonra sekiz karakter uzunluğunda ikinci dizinden (3. karakter) kesilmesi gerekiyordu. Vakaların geri kalanı için, sıfırların eklenmesi sonuca zarar vermez, çünkü yine de keser.
    Math.random().toString(16)+"000000000").substr(2,8).

Montaj:

  • GUID aşağıdaki biçimde XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • GUID'yi 4 parçaya böldüm, her parça 2 türe (veya biçime) ayrıldı: XXXXXXXXve -XXXX-XXXX.
  • Şimdi aşağıdaki gibi, çağrı 4 adet GUID araya getirmek için bu 2 türlerini kullanarak GUID inşa ediyorum: XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • Bu iki tür arasında farklılık göstermek için, bir çift oluşturucu işlevine bir flag parametresi ekledim _p8(s), sparametre işleve tire ekleyip eklemeyeceğini söyler.
  • Sonunda GUID'i aşağıdaki zincirleme ile derleriz: _p8() + _p8(true) + _p8(true) + _p8()ve geri döner.

Blogumdaki bu gönderinin bağlantısı

Zevk almak! :-)


13
Bu uygulama yanlış. GUID'nin bazı karakterleri özel tedavi gerektirir (örn. 13. basamağın 4 sayısı olması gerekir).
JLRishe

67

Chrome'un çarpışmaları için geçici bir çözümle en çok oy alan cevabın bir kombinasyonu :

generateGUID = (typeof(window.crypto) != 'undefined' && 
                typeof(window.crypto.getRandomValues) != 'undefined') ?
    function() {
        // If we have a cryptographically secure PRNG, use that
        // /programming/6906916/collisions-when-generating-uuids-in-javascript
        var buf = new Uint16Array(8);
        window.crypto.getRandomValues(buf);
        var S4 = function(num) {
            var ret = num.toString(16);
            while(ret.length < 4){
                ret = "0"+ret;
            }
            return ret;
        };
        return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));
    }

    :

    function() {
        // Otherwise, just use Math.random
        // /programming/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
            return v.toString(16);
        });
    };

Test etmek istiyorsanız jsbin'de .


3
ilk sürümün, bir `window.crypto.getRandomDeğerleri , does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` verdiğini unutmayın xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
humanityANDpeace

66

ASCII güvenli GUID benzeri benzersiz bir tanımlayıcı oluşturmak için tamamen uyumlu olmayan ancak çok performanslı bir uygulama.

function generateQuickGuid() {
    return Math.random().toString(36).substring(2, 15) +
        Math.random().toString(36).substring(2, 15);
}

26 [a-z0-9] karakter üretir ve RFC uyumlu GUID'lerden hem daha kısa hem de daha benzersiz bir UID sağlar. İnsan tarafından okunabilirlik önemliyse tireler önemsiz bir şekilde eklenebilir.

Bu işlev ve bu sorunun diğer yanıtlarının birçoğu için kullanım örnekleri ve zamanlamaları aşağıda verilmiştir. Zamanlama, her biri 10 milyon yineleme olan Chrome m25 altında gerçekleştirildi.

>>> generateQuickGuid()
"nvcjf1hs7tf8yyk4lmlijqkuo9"
"yq6gipxqta4kui8z05tgh9qeel"
"36dh5sec7zdj90sk2rx7pjswi2"
runtime: 32.5s

>>> GUID() // John Millikin
"7a342ca2-e79f-528e-6302-8f901b0b6888"
runtime: 57.8s

>>> regexGuid() // broofa
"396e0c46-09e4-4b19-97db-bd423774a4b3"
runtime: 91.2s

>>> createUUID() // Kevin Hakanson
"403aa1ab-9f70-44ec-bc08-5d5ac56bd8a5"
runtime: 65.9s

>>> UUIDv4() // Jed Schmidt
"f4d7d31f-fa83-431a-b30c-3e6cc37cc6ee"
runtime: 282.4s

>>> Math.uuid() // broofa
"5BD52F55-E68F-40FC-93C2-90EE069CE545"
runtime: 225.8s

>>> Math.uuidFast() // broofa
"6CB97A68-23A2-473E-B75B-11263781BBE6"
runtime: 92.0s

>>> Math.uuidCompact() // broofa
"3d7b7a06-0a67-4b67-825c-e5c43ff8c1e8"
runtime: 229.0s

>>> bitwiseGUID() // jablko
"baeaa2f-7587-4ff1-af23-eeab3e92"
runtime: 79.6s

>>>> betterWayGUID() // Andrea Turri
"383585b0-9753-498d-99c3-416582e9662c"
runtime: 60.0s

>>>> UUID() // John Fowler
"855f997b-4369-4cdb-b7c9-7142ceaf39e8"
runtime: 62.2s

İşte zamanlama kodu.

var r;
console.time('t'); 
for (var i = 0; i < 10000000; i++) { 
    r = FuncToTest(); 
};
console.timeEnd('t');

62

İşte kullanıcı tarafından bir yorumu da 9 Ekim 2011 tarihli bir çözüm jed en https://gist.github.com/982883 :

UUIDv4 = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}

Bu, mevcut en yüksek puanlı cevapla aynı hedefe ulaşır, ancak zorlama, özyineleme ve üstel gösterimi kullanarak 50'den az bayt. Nasıl çalıştığını merak edenler için, işlevin eski bir sürümünün açıklamalı şekli:

UUIDv4 =

function b(
  a // placeholder
){
  return a // if the placeholder was passed, return
    ? ( // a random number from 0 to 15
      a ^ // unless b is 8,
      Math.random() // in which case
      * 16 // a random number from
      >> a/4 // 8 to 11
      ).toString(16) // in hexadecimal
    : ( // or otherwise a concatenated string:
      [1e7] + // 10000000 +
      -1e3 + // -1000 +
      -4e3 + // -4000 +
      -8e3 + // -80000000 +
      -1e11 // -100000000000,
      ).replace( // replacing
        /[018]/g, // zeroes, ones, and eights with
        b // random hex digits
      )
}

52

Gönderen Sagi'ye shkedy teknik blogu :

function generateGuid() {
  var result, i, j;
  result = '';
  for(j=0; j<32; j++) {
    if( j == 8 || j == 12 || j == 16 || j == 20) 
      result = result + '-';
    i = Math.floor(Math.random()*16).toString(16).toUpperCase();
    result = result + i;
  }
  return result;
}

Bir ActiveX denetimi kullanmayı içeren, ancak bunlardan uzak duran başka yöntemler de vardır!

Düzenleme: Ben hiçbir GUID jeneratör benzersiz anahtarları garanti edemez ( wikipedia makalesine bakın ) işaret değer olduğunu düşündüm . Her zaman çarpışma ihtimali vardır. Bir GUID, çarpışmaların neredeyse sıfır değerine düşürülmesini sağlayacak kadar büyük bir anahtar evreni sunar.


8
Bunun teknik anlamda bir GUID olmadığını unutmayın, çünkü tekliği garanti etmek için hiçbir şey yapmaz. Bu, uygulamanıza bağlı olarak önemli olabilir veya olmayabilir.
Stephen Deken

2
Performans hakkında kısa bir not. Bu çözüm, tek bir sonuç almak için toplam 36 dize oluşturur. Performans kritikse, bir dizi oluşturmayı ve şu şekilde önerildiği gibi katılmayı düşünün: tinyurl.com/y37xtx Daha fazla araştırma bunun önemli olmayabileceğini gösteriyor, bu nedenle YMMV: tinyurl.com/3l7945
Brandon DuRette

2
Benzersizliğe gelince, sürüm 1.3 ve 5 UUID'nin sürüm 4'ün olmadığı gibi belirleyici olduğunu belirtmek gerekir. Bu uuid üreteçlerine (v1'deki düğüm kimliği, v3 ve v5'teki ad alanı ve ad) girişler benzersizse (olması gerektiği gibi), sonuçta ortaya çıkan UUID'ler benzersiz olur. Teoride, her neyse.
broofa

41

Düğüm-uuid kullanabilirsiniz ( https://github.com/kelektiv/node-uuid )

Basit, hızlı nesil RFC4122 UUIDS.

Özellikleri:

  • RFC4122 sürüm 1 veya sürüm 4 UUID'ler oluşturma
  • Node.js ve tarayıcılarda çalışır.
  • Destekleyici platformlarda kriptografik olarak güçlü rastgele # nesil.
  • Küçük ayak izi (küçük şey ister misin? Şuna bakın! )

NPM Kullanarak Yükleme:

npm install uuid

Veya uuid'i tarayıcı aracılığıyla kullanma:

Ham Dosyayı İndir (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Ham Dosyayı İndir (uuid v4): https://raw.githubusercontent.com/kelektiv/node -uuid / ana / v4.js


Daha küçük ister misiniz? Şuna bir göz atın: https://gist.github.com/jed/982883


Kullanımı:

// Generate a v1 UUID (time-based)
const uuidV1 = require('uuid/v1');
uuidV1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'

// Generate a v4 UUID (random)
const uuidV4 = require('uuid/v4');
uuidV4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'

// Generate a v5 UUID (namespace)
const uuidV5 = require('uuid/v5');

// ... using predefined DNS namespace (for domain names)
uuidV5('hello.example.com', v5.DNS)); // -> 'fdda765f-fc57-5604-a269-52a7df8164ec'

// ... using predefined URL namespace (for, well, URLs)
uuidV5('http://example.com/hello', v5.URL); // -> '3bbcee75-cecc-5b56-8031-b6641c1ed1f1'

// ... using a custom namespace
const MY_NAMESPACE = '(previously generated unique uuid string)';
uuidV5('hello', MY_NAMESPACE); // -> '90123e1c-7512-523e-bb28-76fab9f2f73d'

ES6:

import uuid from 'uuid/v4';
const id = uuid();

34
var uuid = function() {
    var buf = new Uint32Array(4);
    window.crypto.getRandomValues(buf);
    var idx = -1;
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        idx++;
        var r = (buf[idx>>3] >> ((idx%8)*4))&15;
        var v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
};

DÜZENLE:

Bu işlevi kullanan ve ayrıntılardan hoşlanmayan projemi tekrar ziyaret ettim. - Ama düzgün rastgelelik gerekiyordu.

Briguy37'nin cevabı ve bazı bitsel operatörlerin arabellekten nibble boyutlu pencereleri çıkartmasına dayanan bir versiyon.

Java'nın UUID'si ile uyumlu olmayan uuidleri ayrıştırmada son kez sorun yaşadığım için RFC Tip 4 (rastgele) şemasına uymalısınız.


31

Bu konudaki en iyi cevapların bir kombinasyonu olarak basit JavaScript modülü.

var crypto = window.crypto || window.msCrypto || null; // IE11 fix

var Guid = Guid || (function() {

  var EMPTY = '00000000-0000-0000-0000-000000000000';

  var _padLeft = function(paddingString, width, replacementChar) {
    return paddingString.length >= width ? paddingString : _padLeft(replacementChar + paddingString, width, replacementChar || ' ');
  };

  var _s4 = function(number) {
    var hexadecimalResult = number.toString(16);
    return _padLeft(hexadecimalResult, 4, '0');
  };

  var _cryptoGuid = function() {
    var buffer = new window.Uint16Array(8);
    window.crypto.getRandomValues(buffer);
    return [_s4(buffer[0]) + _s4(buffer[1]), _s4(buffer[2]), _s4(buffer[3]), _s4(buffer[4]), _s4(buffer[5]) + _s4(buffer[6]) + _s4(buffer[7])].join('-');
  };

  var _guid = function() {
    var currentDateMilliseconds = new Date().getTime();
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(currentChar) {
      var randomChar = (currentDateMilliseconds + Math.random() * 16) % 16 | 0;
      currentDateMilliseconds = Math.floor(currentDateMilliseconds / 16);
      return (currentChar === 'x' ? randomChar : (randomChar & 0x7 | 0x8)).toString(16);
    });
  };

  var create = function() {
    var hasCrypto = crypto != 'undefined' && crypto !== null,
      hasRandomValues = typeof(window.crypto.getRandomValues) != 'undefined';
    return (hasCrypto && hasRandomValues) ? _cryptoGuid() : _guid();
  };

  return {
    newGuid: create,
    empty: EMPTY
  };
})();

// DEMO: Create and show GUID
console.log(Guid.newGuid());

Kullanımı:

Guid.newGuid ()

"C6c2d12f-d76b-5739-e551-07e6de5b0807"

Guid.empty

"00000000-0000-0000-0000-000000000000"


1
Ne hakkında rahatsız tüm cevaplar görünüyor olmasıdır ok JavaScript depolamak için GUIDbir şekilde string. Cevabınız en azından çok daha verimli bir depolama alanı ile a Uint16Array. toStringİşlevi, bir JavaScript ile ikili gösterimini kullanarak olmalıobject
Sebastian

Bu kod tarafından üretilen bu UUID'ler, zayıf ancak RFC uyumlu (_guid) veya güçlü ancak RFC uyumlu değildir (_cryptoGuid). Birincisi, şimdi zayıf bir RNG olduğu bilinen Math.random () kullanır. İkincisi, sürüm ve varyant alanlarını ayarlayamıyor.
broofa

@broofa - Güçlü ve RFC uyumlu hale getirmek için ne önerirsiniz ? Ve _cryptoGuid neden RFC uyumlu değil?
Matt

@Matt _cryptoGuid () 128 bitin tümünü rastgele ayarlar, yani sürüm ve varyant alanlarını RFC'de açıklandığı gibi ayarlamaz. Güçlü ve uyumlu bir uygulama için yukarıdaki en yüksek oy alan yanıtımda crypto.getRandomValues ​​() kullanan alternatif uuidv4 () uygulamamı inceleyin.
Broofa

29

Bu, sürüm 4 UUID (sözde rasgele sayılardan oluşturulan) oluşturur:

function uuid()
{
   var chars = '0123456789abcdef'.split('');

   var uuid = [], rnd = Math.random, r;
   uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
   uuid[14] = '4'; // version 4

   for (var i = 0; i < 36; i++)
   {
      if (!uuid[i])
      {
         r = 0 | rnd()*16;

         uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf];
      }
   }

   return uuid.join('');
}

Oluşturulan UUID'lerin bir örneği:

682db637-0f31-4847-9cdf-25ba9613a75c
97d19478-3ab2-4aa1-b8cc-a1c3540f54aa
2eed04c9-2692-456d-a0fd-51012f947136

28

Bunun zaten bir sürü cevabı var, ama ne yazık ki grupta "gerçek" bir rastgele yok. Aşağıdaki sürüm, broofa'nın cevabının bir uyarlamasıdır, ancak mevcut olduğunda kripto kitaplıklarını kullanan "gerçek" rastgele bir işlevi ve yedek olarak Alea () işlevini içerecek şekilde güncellenmiştir.

  Math.log2 = Math.log2 || function(n){ return Math.log(n) / Math.log(2); }
  Math.trueRandom = (function() {
  var crypt = window.crypto || window.msCrypto;

  if (crypt && crypt.getRandomValues) {
      // if we have a crypto library, use it
      var random = function(min, max) {
          var rval = 0;
          var range = max - min;
          if (range < 2) {
              return min;
          }

          var bits_needed = Math.ceil(Math.log2(range));
          if (bits_needed > 53) {
            throw new Exception("We cannot generate numbers larger than 53 bits.");
          }
          var bytes_needed = Math.ceil(bits_needed / 8);
          var mask = Math.pow(2, bits_needed) - 1;
          // 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111

          // Create byte array and fill with N random numbers
          var byteArray = new Uint8Array(bytes_needed);
          crypt.getRandomValues(byteArray);

          var p = (bytes_needed - 1) * 8;
          for(var i = 0; i < bytes_needed; i++ ) {
              rval += byteArray[i] * Math.pow(2, p);
              p -= 8;
          }

          // Use & to apply the mask and reduce the number of recursive lookups
          rval = rval & mask;

          if (rval >= range) {
              // Integer out of acceptable range
              return random(min, max);
          }
          // Return an integer that falls within the range
          return min + rval;
      }
      return function() {
          var r = random(0, 1000000000) / 1000000000;
          return r;
      };
  } else {
      // From https://web.archive.org/web/20120502223108/http://baagoe.com/en/RandomMusings/javascript/
      // Johannes Baagøe <baagoe@baagoe.com>, 2010
      function Mash() {
          var n = 0xefc8249d;

          var mash = function(data) {
              data = data.toString();
              for (var i = 0; i < data.length; i++) {
                  n += data.charCodeAt(i);
                  var h = 0.02519603282416938 * n;
                  n = h >>> 0;
                  h -= n;
                  h *= n;
                  n = h >>> 0;
                  h -= n;
                  n += h * 0x100000000; // 2^32
              }
              return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
          };

          mash.version = 'Mash 0.9';
          return mash;
      }

      // From http://baagoe.com/en/RandomMusings/javascript/
      function Alea() {
          return (function(args) {
              // Johannes Baagøe <baagoe@baagoe.com>, 2010
              var s0 = 0;
              var s1 = 0;
              var s2 = 0;
              var c = 1;

              if (args.length == 0) {
                  args = [+new Date()];
              }
              var mash = Mash();
              s0 = mash(' ');
              s1 = mash(' ');
              s2 = mash(' ');

              for (var i = 0; i < args.length; i++) {
                  s0 -= mash(args[i]);
                  if (s0 < 0) {
                      s0 += 1;
                  }
                  s1 -= mash(args[i]);
                  if (s1 < 0) {
                      s1 += 1;
                  }
                  s2 -= mash(args[i]);
                  if (s2 < 0) {
                      s2 += 1;
                  }
              }
              mash = null;

              var random = function() {
                  var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
                  s0 = s1;
                  s1 = s2;
                  return s2 = t - (c = t | 0);
              };
              random.uint32 = function() {
                  return random() * 0x100000000; // 2^32
              };
              random.fract53 = function() {
                  return random() +
                      (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
              };
              random.version = 'Alea 0.9';
              random.args = args;
              return random;

          }(Array.prototype.slice.call(arguments)));
      };
      return Alea();
  }
}());

Math.guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c)    {
      var r = Math.trueRandom() * 16 | 0,
          v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
  });
};

27

GitHub'daki JavaScript projesi - https://github.com/LiosK/UUID.js

UUID.js JavaScript için RFC uyumlu UUID üreticisi.

Bkz. RFC 4122 http://www.ietf.org/rfc/rfc4122.txt .

Features RFC 4122 uyumlu UUID'ler oluşturur.

Sürüm 4 UUID'ler (rastgele sayılardan UUID'ler) ve sürüm 1 UUID'ler (zaman tabanlı UUID'ler) kullanılabilir.

UUID nesnesi, UUID alanlarına erişim dahil UUID'ye çeşitli erişim sağlar.

JavaScript'in düşük zaman damgası çözünürlüğü rastgele sayılarla telafi edilir.


21
  // RFC 4122
  //
  // A UUID is 128 bits long
  //
  // String representation is five fields of 4, 2, 2, 2, and 6 bytes.
  // Fields represented as lowercase, zero-filled, hexadecimal strings, and
  // are separated by dash characters
  //
  // A version 4 UUID is generated by setting all but six bits to randomly
  // chosen values
  var uuid = [
    Math.random().toString(16).slice(2, 10),
    Math.random().toString(16).slice(2, 6),

    // Set the four most significant bits (bits 12 through 15) of the
    // time_hi_and_version field to the 4-bit version number from Section
    // 4.1.3
    (Math.random() * .0625 /* 0x.1 */ + .25 /* 0x.4 */).toString(16).slice(2, 6),

    // Set the two most significant bits (bits 6 and 7) of the
    // clock_seq_hi_and_reserved to zero and one, respectively
    (Math.random() * .25 /* 0x.4 */ + .5 /* 0x.8 */).toString(16).slice(2, 6),

    Math.random().toString(16).slice(2, 14)].join('-');

16

Broofa'nın cevabını anlamak istedim, bu yüzden genişlettim ve yorum ekledim:

var uuid = function () {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
        /[xy]/g,
        function (match) {
            /*
            * Create a random nibble. The two clever bits of this code:
            *
            * - Bitwise operations will truncate floating point numbers
            * - For a bitwise OR of any x, x | 0 = x
            *
            * So:
            *
            * Math.random * 16
            *
            * creates a random floating point number
            * between 0 (inclusive) and 16 (exclusive) and
            *
            * | 0
            *
            * truncates the floating point number into an integer.
            */
            var randomNibble = Math.random() * 16 | 0;

            /*
            * Resolves the variant field. If the variant field (delineated
            * as y in the initial string) is matched, the nibble must
            * match the mask (where x is a do-not-care bit):
            *
            * 10xx
            *
            * This is achieved by performing the following operations in
            * sequence (where x is an intermediate result):
            *
            * - x & 0x3, which is equivalent to x % 3
            * - x | 0x8, which is equivalent to x + 8
            *
            * This results in a nibble between 8 inclusive and 11 exclusive,
            * (or 1000 and 1011 in binary), all of which satisfy the variant
            * field mask above.
            */
            var nibble = (match == 'y') ?
                (randomNibble & 0x3 | 0x8) :
                randomNibble;

            /*
            * Ensure the nibble integer is encoded as base 16 (hexadecimal).
            */
            return nibble.toString(16);
        }
    );
};

Ayrıntılı açıklama için teşekkürler! Özellikle eşdeğer açıklama ile 8 ve 11 arasında kafeslenmiş kemirmek süper yardımcı olur.
Egor Litvinchuk

15

Burada bazı ekstralar ile kendi UUID / GUID jeneratör ayarlandı .

Aşağıdaki Kybos rasgele sayı üretecini biraz daha kriptografik olarak kullanmak için kullanıyorum .

Aşağıda baagoe.com'dan Mash ve Kybos yöntemleri ile senaryom hariç.

//UUID/Guid Generator
// use: UUID.create() or UUID.createSequential()
// convenience:  UUID.empty, UUID.tryParse(string)
(function(w){
  // From http://baagoe.com/en/RandomMusings/javascript/
  // Johannes Baagøe <baagoe@baagoe.com>, 2010
  //function Mash() {...};

  // From http://baagoe.com/en/RandomMusings/javascript/
  //function Kybos() {...};

  var rnd = Kybos();

  //UUID/GUID Implementation from http://frugalcoder.us/post/2012/01/13/javascript-guid-uuid-generator.aspx
  var UUID = {
    "empty": "00000000-0000-0000-0000-000000000000"
    ,"parse": function(input) {
      var ret = input.toString().trim().toLowerCase().replace(/^[\s\r\n]+|[\{\}]|[\s\r\n]+$/g, "");
      if ((/[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}/).test(ret))
        return ret;
      else
        throw new Error("Unable to parse UUID");
    }
    ,"createSequential": function() {
      var ret = new Date().valueOf().toString(16).replace("-","")
      for (;ret.length < 12; ret = "0" + ret);
      ret = ret.substr(ret.length-12,12); //only least significant part
      for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
      return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
    }
    ,"create": function() {
      var ret = "";
      for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
      return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
    }
    ,"random": function() {
      return rnd();
    }
    ,"tryParse": function(input) {
      try {
        return UUID.parse(input);
      } catch(ex) {
        return UUID.empty;
      }
    }
  };
  UUID["new"] = UUID.create;

  w.UUID = w.Guid = UUID;
}(window || this));

15

Hızla ilgili rfc4122 sürüm 4 uyumlu bir çözüm isteyenler için (Math.random () için birkaç çağrı):

var rand = Math.random;

function UUID() {
    var nbr, randStr = "";
    do {
        randStr += (nbr = rand()).toString(16).substr(3, 6);
    } while (randStr.length < 30);
    return (
        randStr.substr(0, 8) + "-" +
        randStr.substr(8, 4) + "-4" +
        randStr.substr(12, 3) + "-" +
        ((nbr*4|0)+8).toString(16) + // [89ab]
        randStr.substr(15, 3) + "-" +
        randStr.substr(18, 12)
    );
}

console.log( UUID() );

Yukarıdaki fonksiyonun hız ve rastgelelik arasında iyi bir dengesi olmalıdır.


13

ES6 örneği

const guid=()=> {
  const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);     
  return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
}

12

Daha iyi bir yol:

function(
  a,b                // placeholders
){
  for(               // loop :)
      b=a='';        // b - result , a - numeric variable
      a++<36;        // 
      b+=a*51&52  // if "a" is not 9 or 14 or 19 or 24
                  ?  //  return a random number or 4
         (
           a^15      // if "a" is not 15
              ?      // genetate a random number from 0 to 15
           8^Math.random()*
           (a^20?16:4)  // unless "a" is 20, in which case a random number from 8 to 11
              :
           4            //  otherwise 4
           ).toString(16)
                  :
         '-'            //  in other cases (if "a" is 9,14,19,24) insert "-"
      );
  return b
 }

Minimize edilmiş:

function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b}

11

Biliyorum, bu eski bir soru. Sadece eksiksizlik için, ortamınız SharePoint ise, SP.Guid.newGuid( msdn link ) adında yeni bir kılavuz oluşturan bir yardımcı program işlevi vardır . Bu işlev sp.init.js dosyasının içindedir. Bu işlevi yeniden yazarsanız (diğer özel işlevlerden diğer bazı bağımlılıkları kaldırmak için), şöyle görünür:

var newGuid = function () {
    var result = '';
    var hexcodes = "0123456789abcdef".split("");

    for (var index = 0; index < 32; index++) {
        var value = Math.floor(Math.random() * 16);

        switch (index) {
        case 8:
            result += '-';
            break;
        case 12:
            value = 4;
            result += '-';
            break;
        case 16:
            value = value & 3 | 8;
            result += '-';
            break;
        case 20:
            result += '-';
            break;
        }
        result += hexcodes[value];
    }
    return result;
};

11

Bu, tarihe dayanır ve benzersizliği "sağlamak" için rastgele bir sonek ekler. CSS tanımlayıcıları için iyi çalışır. Her zaman böyle bir şey döndürür ve hacklenmesi kolaydır:

uid-139410573297741

var getUniqueId = function (prefix) {
            var d = new Date().getTime();
            d += (parseInt(Math.random() * 100)).toString();
            if (undefined === prefix) {
                prefix = 'uid-';
            }
            d = prefix + d;
            return d;
        };

11

Basit kod that use crypto.getRandomValues(a)üzerinde desteklenen tarayıcılar (IE11 + iOS7 +, FF21 +, Chrome, Android Chrome). Kullanmayı önler Math.random()çünkü bu çarpışmalara neden olabilir (örneğin, Muxa tarafından gerçek bir durumda 4000 üretilen uuid için 20 çarpışma ).

function uuid() {
    function randomDigit() {
        if (crypto && crypto.getRandomValues) {
            var rands = new Uint8Array(1);
            crypto.getRandomValues(rands);
            return (rands[0] % 16).toString(16);
        } else {
            return ((Math.random() * 16) | 0).toString(16);
        }
    }
    var crypto = window.crypto || window.msCrypto;
    return 'xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx'.replace(/x/g, randomDigit);
}

Notlar:

  • Kod okunabilirliği hız için değil, saniyede birkaç yüz uuid için uygundur. Performansı ölçmek için http://jsbin.com/fuwigo/1 adresini kullanarak dizüstü bilgisayarımda Chromium'da saniyede yaklaşık 10000 uuid () oluşturur .
  • Kod okunabilirliğini basitleştirdiği için yalnızca "y" için 8 kullanır (y'nin 8, 9, A veya B olmasına izin verilir).

11

Belirli bir biçimde rastgele bir 128 bit dizeye ihtiyacınız varsa kullanabilirsiniz:

function uuid() {
    return crypto.getRandomValues(new Uint32Array(4)).join('-');
}

Hangi gibi bir şey dönecektir 2350143528-4164020887-938913176-2513998651.


BTW, neden sadece karakter değil, sadece sayı üretiyor? çok daha az güvenli
vsync

1
ayrıca şöyle karakterler (harfler) ekleyebilirsiniz:Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
magikMaker

11

Sadece iki mutasyona sahip daha okunabilir bir varyant.

function uuid4()
{
  function hex (s, b)
  {
    return s +
      (b >>> 4   ).toString (16) +  // high nibble
      (b & 0b1111).toString (16);   // low nibble
  }

  let r = crypto.getRandomValues (new Uint8Array (16));

  r[6] = r[6] >>> 4 | 0b01000000; // Set type 4: 0100
  r[8] = r[8] >>> 3 | 0b10000000; // Set variant: 100

  return r.slice ( 0,  4).reduce (hex, '' ) +
         r.slice ( 4,  6).reduce (hex, '-') +
         r.slice ( 6,  8).reduce (hex, '-') +
         r.slice ( 8, 10).reduce (hex, '-') +
         r.slice (10, 16).reduce (hex, '-');
}

Eh js devs çoğu web geliştiriciler ve biz bitwise operatörlerin ne yaptığını anlamayacağım, çünkü biz çoğu zaman biz onları geliştirmek kullanmıyoruz. Aslında bunlardan hiçbirine ihtiyacım olmadı ve '97'den beri js devim. Yani örnek kodunuz hala okuyacak ortalama bir web geliştiricisi tarafından okunamıyor. Hala tek harfli değişken adları kullandığınızdan bahsetmiyoruz, bu da onu daha şifreli hale getiriyor. Muhtemelen Temiz Kod'u okuyun, belki de yardımcı olur: amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/…
inf3rno

@ inf3rno onu bash etmeyin, bu iş parçacığında önerilen tüm çözümler şifreli ama soru bir çeşit liner olması düşünülürse doğru cevaplar. tek gömlekler şifreli. ortalama geliştiriciye okunabilir durumda değiller, ancak basit bir önceki yorumun yapacağı ekran gayrimenkulünü kaydediyorlar. Sonuç olarak, bunun yerine "okunabilir kod" da olsaydı, bu şekilde çok daha okunabilir olur.
tatsu

Rastgele! = Benzersiz
user1529413

@ user1529413 Evet. Benzersizlik bir indeks gerektirir.
ceving

Bu benim en sevdiğim cevap, çünkü 16 baytlık (128 bit) bir değer olarak bir UUID oluşturuyor ve seri hale getirilmiş, okunması hoş bir form değil. String öğelerini bırakmak ve sadece bir uuidv4'ün olması gereken rastgele bir 128bit'in doğru bitlerini ayarlamak son derece kolay olurdu. Daha kısa URL'ler için temel alabilir, bazı web montajlarına geri aktarabilir, bir dizeden daha az bellek alanında saklayabilir, 4096 boyutlu bir tampon yapabilir ve 256 uuid koyabilir, bir tarayıcı db, vb. Saklayabilirsiniz. her şeyi başlangıçtan itibaren uzun, küçük harfli onaltılık kodlanmış bir dizge olarak kullanmaktan daha fazla.
Qaribou'dan Josh

8

Tamam, uuid paketi kullanarak , sürüm 1, 3, 4 ve 5 UUID'leri destekler :

yarn add uuid

ve sonra:

const uuidv1 = require('uuid/v1');
uuidv1(); // ⇨ '45745c60-7b1a-11e8-9c9c-2d42b21b1a3e'

Bunu tam olarak belirtilen seçeneklerle de yapabilirsiniz:

const v1options = {
  node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],
  clockseq: 0x1234,
  msecs: new Date('2011-11-01').getTime(),
  nsecs: 5678
};
uuidv1(v1options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab'

Daha fazla bilgi için, npm sayfasını ziyaret buraya


6

Bunun için kendi eşyalarınızı kırmak yerine 1'den fazla katılımcı tarafından korunan iyi test edilmiş kod kullanmanız önemlidir. Bu, muhtemelen X tarayıcısında çalışan ancak Y'yi sezgiselleştirmelerini hesaba katmayan, genellikle hataları rastgele araştırmaktan çok zorlaştıran en kararlı kodu tercih etmek istediğiniz yerlerden biridir. bazı kullanıcılar için. Şahsen ben uuid-js https://github.com/aurigadl/uuid-js adresinden kullanıyorum .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.