GUID / UUID를 만드는 방법?


4176

JavaScript로 전역 고유 식별자를 만들려고합니다. 모든 브라우저에서 어떤 루틴을 사용할 수 있는지, 내장 난수 생성기가 어떻게 "랜덤"되고 시드되었는지 잘 모르겠습니다.

GUID / UUID는 32 자 이상이어야하며 ASCII 범위를 유지하여 전달할 때 문제가 발생하지 않도록해야합니다.


13
문자열로 반복되는 GUID는 길이가 최소 36 자에서 38자를 넘지 않고 ^ \ {? [a-zA-Z0-9] {36}? \} $ 패턴과 일치하므로 항상 ASCII입니다.
AnthonyWJones


아무도 아직 이것을 언급하지 않았지만 완전성을 위해 npm 에는 많은 guid 생성기가 있습니다. 대부분 브라우저에서 작동한다고 생각합니다.
George Mauer

답변:


2338

RFC 4122 에 따르면 GUID (Globally Unique IDentifier)라고도하는 UUID (Universally Unique IDentifier) 는 특정 고유성을 보장하도록 설계된 식별자입니다.

몇 줄의 JS에서 RFC 호환 UUID를 구현할 수 있지만 (예 : @broofa의 답변 참조) 몇 가지 일반적인 함정이 있습니다.

  • 잘못된 ID 형식 (UUID는 " xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx" 형식이어야합니다 . 여기서 x는 [0-9, af] 중 하나임) 중 하나이고 M 은 [1-5] 중 하나이고 N 은 [8, 9, a 또는 b] 임 )
  • 난수의 낮은 품질의 소스 코드의 사용 (예 Math.random)

따라서 프로덕션 환경을위한 코드를 작성하는 개발자는 uuid 모듈 과 같이 엄격하고 잘 관리 된 구현을 사용하는 것이 좋습니다 .


186
실제로 RFC는 임의의 숫자로 작성된 UUID를 허용합니다. 이를 식별하기 위해 몇 비트 만 돌리면됩니다. 4.4 절을 참조하십시오. 정말 랜덤 또는 의사 난수에서 UUID 생성을위한 알고리즘 : rfc-archive.org/getrfc.php?rfc=4122
제이슨 DeFontes

이 스레드의 모든 것을 기반으로 이미 아래의 "e7"변형보다 두 배 빠른 버전을 만들었습니다. 암호는 강력하며 모든 주요 브라우저와 노드에서 작동합니다. 여기에 포함하기에는 너무 큽니다. 2020 년 5 월 17 일에 제 이름으로 새로운 답변을 찾으십시오.
Bennett Barouch

노드 UUID 지금이되었다 UUID (후자 프로젝트에 병합 후)
Catweazle

4110

을 위해 RFC4122의 버전 4 준수 솔루션이 한 줄 (틱) 솔루션은 내가 가지고 올 수있는 가장 컴팩트 :

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());

2015-06-02 업데이트 : UUID 고유성은 기본 난수 생성기 (RNG)에 크게 의존합니다. 위의 솔루션 Math.random()은 간결성을 위해 사용 되지만 고품질 RNG Math.random()아닙니다 . 자세한 내용은 Adam Hyland의 Math.random ()에 대한 훌륭한 글 을 참조하십시오. 보다 강력한 솔루션을 위해서는 uuid 모듈 사용을 고려하십시오 위해서는 고품질 RNG API를 사용 .

업데이트, 2015년 8월 26일는 : 사이드 참고로,이 요점은 충돌의 특정 확률에 도달하기 전에 생성 할 수 있습니다 얼마나 많은 ID를 확인하는 방법에 대해 설명합니다. 예를 들어 3.26x10 15 버전 4 RFC4122 UUID를 사용하면 1 백만 분의 1의 충돌 가능성이 있습니다.

2017-06-28 업데이트 : Chrome 개발자 가 Chrome, Firefox 및 Safari의 Math.random PRNG 품질 상태를 논의한 좋은 기사입니다 . tl; dr-2015 년 말 기준으로 "아주 훌륭"하지만 암호화 품질은 아닙니다. 이 문제를 해결하기 위해 ES6, cryptoAPI 및 약간의 JS 마법사 를 사용하는 위 솔루션의 업데이트 된 버전은 다음 과 같습니다.

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());

2020-01-06 업데이트 : JS 언어의 일부로 표준 모듈 작업에 대한 제안이uuid 있습니다.


30
충돌에 관한 질문을 게시했습니다 stackoverflow.com/questions/6906916/…
Muxa

4
@marc-Math.random ()의 품질이 중요합니다. 그러나 x- 브라우저가 거의 변하는 기본 구현에 대한 자세한 분석이 없으면 실제 충돌 확률을 알 수 없습니다. 그래서 단순성을 위해 이상적인 랜덤 소스를 가정합니다. 그러나, 그것은 muxa의 문제가 강조하는 것처럼 위험한 가정 일 수 있습니다. 또한 node-uuid ( github.com/broofa/node-uuid )에서 Math.random ()에 비해 암호화 품질의 무작위성을 보장하는 다른 API를 선호하지만 성능이 저하됩니다.
broofa

144
@Muxa의 질문에 대한 대답은 '아니요'입니까? 클라이언트에서 온 것을 신뢰하는 것은 결코 안전하지 않습니다. 사용자가 자바 스크립트 콘솔을 가져 와서 원하는 것으로 변수를 수동으로 변경 할 가능성에 달려 있다고 생각합니다. 또는 원하는 ID를 게시 할 수 있습니다. 또한 사용자가 자신의 ID를 선택하여 취약점을 유발하는지 여부에 따라 다릅니다. 어느 쪽이든, 테이블에 들어가는 난수 ID 인 경우 서버 측에서 생성하여 프로세스를 제어 할 수 있음을 알 수 있습니다.
캠 잭슨

36
@DrewNoakes-UUID는 단순한 무작위 #의 문자열이 아닙니다. "4"는 UUID 버전입니다 (4 = "무작위"). "y"는 UUID 변형 (기본적으로 필드 레이아웃)이 포함되어야하는 위치를 나타냅니다. 자세한 내용은 ietf.org/rfc/rfc4122.txt의 섹션 4.1.1 및 4.1.3을 참조하십시오 .
broofa

5
c== 'x'대신에 c === 'x'. jshint가 실패했기 때문입니다.
Fizer Khan

810

나는 Broofa의 대답 이 얼마나 깨끗한 정말 좋아 하지만 불행히도 구현Math.random잘못 되면 충돌의 가능성이 있습니다.

다음 은 타임 스탬프의 16 진 부분으로 처음 13 개의 16 진수를 오프셋하고 페이지로드 이후 마이크로 초의 16 진 부분으로 오프셋을 고갈 시켜서이 문제를 해결 하는 유사한 RFC4122 버전 4 호환 솔루션입니다. 이렇게 Math.random하면 동일한 시드에 있더라도 두 클라이언트 모두 페이지로드 이후 (고성능 시간이 지원되는 경우) 이후 정확히 동일한 밀리 초 (또는 10,000 년 이상) 후 UUID를 정확히 동일한 수의 마이크로 초로 생성해야합니다. 동일한 UUID를 얻으십시오.

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())


테스트 할 바이올린이 있습니다.


31
명심하십시오, new Date().getTime()매 밀리 초마다 업데이트되지는 않습니다. 이것이 알고리즘의 예상 무작위성에 어떤 영향을 미치는지 잘 모르겠습니다.
devios1

84
성능 이 향상되었습니다. Date.now와 달리 반환되는 타임 스탬프는 performance.now()1 밀리 초 해상도로 제한되지 않습니다. 대신 시간을 최대 마이크로 초 정밀도의 부동 소수점 숫자로 나타냅니다 . 또한 Date.now와 달리 performance.now ()에 의해 반환되는 값은 수동으로 조정되거나 네트워크 시간 프로토콜과 같은 소프트웨어에 의해 기울어 질 수있는 시스템 클록에 관계 없이 항상 일정한 속도로 증가 합니다.
daniellmb

6
@daniellmb 아마 polyfill이 아닌 실제 문서를 보여주기 위해 MDN이나 다른 링크에 링크했을 것입니다.)
Martin

2
사용 반올림이 무엇인지 알 수 d = Math.floor(d/16);있습니까?
Praveen

2
@Praveen이 작업은 타임 스탬프를 16 진수 한 자리 오른쪽으로 이동하고 나머지는 삭제합니다. 그 목적은 방금 사용한 16 진수 (최소 수)를 제거하고 다음 반복을 위해 준비하는 것입니다.
Briguy37

431

broofa의 대답은 실제로 매끄럽고 매끄 럽습니다 .rfc4122 호환, 다소 읽기 쉽고 컴팩트합니다. 대박!

그러나 그 정규 표현식, 많은 replace()콜백, toString()Math.random()함수 호출 (그가 4 비트의 결과 만 사용하고 나머지는 낭비하는 곳)을 보고 있다면 성능에 대해 궁금해 할 수 있습니다. 실제로 joelpt는로 일반 GUID 속도를 위해 RFC를 포기하기로 결정했습니다 generateQuickGUID.

그러나 속도 RFC 준수를 얻을 수 있습니까? 나는 찬성! 가독성을 유지할 수 있습니까? 글쎄 ... 실제로는 아니지만 따라 가면 쉽다.

그러나 먼저, 내 결과는 broofa guid(허용 된 답변) 및 비 rfc 호환과 비교되었습니다 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 번의 최적화 반복으로 12X 이상으로 가장 인기있는 답변 , 9X 이상으로 허용되는 답변 및 2-3X로 빠른 비준수 답변을 이겼습니다. . 그리고 나는 여전히 rfc4122를 준수합니다.

방법에 관심이 있습니까? http://jsfiddle.net/jcward/7hyaC/3/http://jsperf.com/uuid-generator-opt/4 에 전체 소스를 넣었습니다.

설명을 위해, broofa의 코드로 시작해 봅시다 :

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())

따라서 x임의의 16 진수로, y임의의 데이터 ( 10RFC 사양 에 따라 상위 2 비트를 강제로 제외)를 대체 하며 정규 표현식은 문자 -또는 4문자 와 일치 하지 않으므로 처리 할 필요가 없습니다. 매우 매끄 럽습니다.

가장 먼저 알아야 할 것은 정규 표현식과 마찬가지로 함수 호출이 비싸다는 것입니다 (1을 사용하지만 각 일치에 대해 하나씩 32 개의 콜백이 있으며 각 32 개의 콜백에서 Math.random () 및 v를 호출합니다. toString (16)).

성능을 향한 첫 단계는 RegEx와 콜백 함수를 제거하고 대신 간단한 루프를 사용하는 것입니다. 이것은 broofa가 아닌 반면에 -and 를 처리해야 함을 의미 4합니다. 또한 String Array 인덱싱을 사용하여 매끄러운 String 템플릿 아키텍처를 유지할 수 있습니다.

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())

기본적으로, 동일한 내부 로직, 우리는 제외시켰다 확인 -하거나 4, 잠시 루프를 사용하여 (대신replace() 콜백 것은) 우리에게 거의 3 배 개선을 얻는다!

다음 단계는 데스크톱에서는 작은 단계이지만 모바일에서는 상당한 차이가 있습니다. 더 적은 Math.random () 호출을 만들고 각 반복마다 시프트되는 임의 버퍼로 87 %를 버리지 않고 모든 임의의 비트를 활용합시다. 다음과 같은 경우를 대비하여 해당 템플리트 정의를 루프 밖으로 이동 시키십시오.

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())

이는 플랫폼에 따라 10-30 %를 절약합니다. 나쁘지 않다. 그러나 다음 큰 단계는 최적화 클래식 인 조회 테이블과 함께 toString 함수 호출을 완전히 제거합니다. 간단한 16 요소 룩업 테이블은 훨씬 짧은 시간에 toString (16) 작업을 수행합니다.

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())

다음 최적화는 또 다른 고전입니다. 각 루프 반복에서 4 비트의 출력 만 처리하므로 루프 수를 반으로 줄이고 각 반복마다 8 비트를 처리하겠습니다. 여전히 RFC 호환 비트 위치를 처리해야하기 때문에 까다로울 수 있지만 그렇게 어렵지는 않습니다. 그런 다음 0x00-0xff를 저장하기 위해 더 큰 조회 테이블 (16x16 또는 256)을 만들어야하며 e5 () 함수 외부에서 한 번만 작성합니다.

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())

나는 여전히 256 요소 LUT를 사용하여 한 번에 16 비트를 처리하는 e6 ()을 시도했으며 최적화의 감소 수익을 보여주었습니다. 반복 횟수는 적었지만 내부 로직은 처리 증가로 인해 복잡해졌으며 데스크톱에서도 동일하게 수행되었으며 모바일에서는 ~ 10 % 더 빨랐습니다.

적용 할 최종 최적화 기술-루프를 전개하십시오. 우리는 고정 된 횟수로 반복하기 때문에 기술적으로 이것을 모두 손으로 작성할 수 있습니다. 나는 다시 할당하고 성능을 향상시키는 단일 무작위 변수 r로 이것을 한 번 시도했다. 그러나 4 개의 변수에 임의의 데이터를 미리 할당 한 다음 조회 테이블을 사용하고 적절한 RFC 비트를 적용하면이 버전이 모두 담배를 피 웁니다.

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())

Modualized : http://jcward.com/UUID.js -UUID.generate()

재미있는 점은 16 바이트의 임의 데이터를 생성하는 것이 쉽다는 것입니다. 전체 트릭은 RFC 준수를 사용하여 문자열 형식으로 표현하며 16 바이트의 임의 데이터, 롤링되지 않은 루프 및 조회 테이블을 사용하여 가장 엄격하게 수행됩니다.

나는 나의 논리가 정확하기를 희망한다. 이런 종류의 지루한 비트 작업에서 실수를 저지르는 것은 매우 쉽다. 그러나 출력은 나에게 좋아 보인다. 코드 최적화를 통해이 미친 듯이 즐거운 시간을 보내시기 바랍니다.

조언 : 나의 주요 목표는 잠재적 인 최적화 전략을 보여주고 가르치는 것이 었습니다. 다른 답변은 충돌 및 진정한 난수와 같은 중요한 주제를 다루며, 이는 좋은 UUID를 생성하는 데 중요합니다.


14
이 코드에는 여전히 몇 가지 오류가 있습니다. Math.random()*0xFFFFFFFF행은 Math.random()*0x100000000완전한 임의성을 >>>0가져야하며 |0값을 부호가없는 상태로 유지하는 대신 사용해야합니다 (현재 코드는 서명되어 있어도 괜찮습니다). 마지막으로 요즘에는 사용 window.crypto.getRandomValues가능한 경우 사용 하는 것이 좋으며 반드시 필요한 경우에만 Math.random으로 대체하는 것이 좋습니다. Math.random은 128 비트 미만의 엔트로피를 가질 수 있으며,이 경우 필요한 것보다 충돌에 더 취약합니다.
Dave

이 스레드에 이미있는 모든 것을 기반으로 노드를 포함한 모든 환경을 이식 할 수있는 "e7"보다 두 배 빠른 속도로 무언가를 구축했으며 Math.random ()에서 crypto-strength randomness로 업그레이드되었습니다. UUID에 암호화 강도가 필요하다고 생각하지는 않지만 UUID의 전체 지점 인 충돌 가능성이 훨씬 적습니다. 의견에 맞추기에는 너무 커서 별도로 게시했습니다.
Bennett Barouch

164

다음은 RFC 4122 , 섹션 4.4 (정확히 임의 또는 의사 난수에서 UUID를 작성하기위한 알고리즘)를 기반으로하는 일부 코드 입니다.

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를 만들 때 배열 크기를 동적으로 조정하지 않고 미리 배열 크기를 선언해야합니다. var s = new Array(36);
MgSam

1
라인에 clock_seq_hi_and_reserved의 비트 비트 6-7을 01로 설정하는 매우 작은 버그가 있다고 생각합니다. s [19]는 문자 '0'.. 'f'이고 int 0x0..0xf가 아니기 때문에 (s [19] & 0x3) | 0x8은 무작위로 배포되지 않습니다-더 많은 '9'와 더 적은 'b'를 생성하는 경향이 있습니다. 어떤 이유로 임의 분포에 관심이있는 경우에만 차이가 있습니다.
John Velonis

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

ID가 1 밀리 초 이상 생성되면 100 % 고유합니다.

짧은 간격으로 두 개의 ID가 생성되고 임의 방법이 실제로 무작위라고 가정하면 전 세계적으로 고유 할 가능성이있는 99.99999999999999 % 인 ID를 생성합니다 (10 ^ 15 중 1의 충돌).

더 많은 자릿수를 추가하여이 수를 늘릴 수 있지만 100 % 고유 ID를 생성하려면 글로벌 카운터를 사용해야합니다.

RFC 호환성이 필요한 경우이 형식은 유효한 버전 4 GUID로 전달됩니다.

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('-');

편집 : 위의 코드는 의도를 따르지 만 RFC의 글자는 아닙니다. 다른 불일치 중에는 임의의 숫자가 짧습니다. (필요한 경우 임의의 숫자를 더 추가하십시오.) 거꾸로하면 이것이 정말 빠릅니다. GUID의 유효성을 테스트 할 수 있습니다.


4
이것은 UUID가 아닙니다?
Marco Kerwitz

UUID / GUID는 122 비트 (+ 6 개의 예약 된 비트) 숫자입니다. 글로벌 카운터 서비스를 통해 고유성을 보장 할 수 있지만, 종종 정시, MAC 주소 및 임의성을 중계합니다. UUID는 무작위가 아닙니다! 여기서 제안하는 UID는 완전히 압축되지 않았습니다. 압축을 122 비트 정수로 압축하고 6 개의 미리 정의 된 비트와 여분의 임의 비트를 추가하고 (몇 개의 타이머 비트를 제거) 완벽하게 형성된 UUID / GUID로 끝내면 16 진수로 변환해야합니다. 나에게 그것은 ID의 길이에 대한 준수 이외의 것을 추가하지 않습니다.
Simon Rigét

5
가상 머신에서 고유성을 위해 MAC 주소를 릴레이하는 것은 나쁜 생각입니다!
Simon Rigét

1
나는 이와 같은 일을하지만 앞의 문자와 일부 대시 (예 : [slug, date, random].join("_")를 생성하기 위해)를 사용 usr_1dcn27itd_hj6onj6phr합니다.이를 통해 id가 "만들기"필드로도 두 배가됩니다
Seph Reed

95

형식에서 문자열 생성기 방식과 같은 가장 빠른 GUID XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. 표준 호환 GUID는 생성하지 않습니다.

이 구현의 천만 번의 실행은 32.5 초 밖에 걸리지 않습니다. 이는 브라우저에서 가장 빠른 속도입니다 (루프 / 반복없는 유일한 솔루션).

이 기능은 다음과 같이 간단합니다.

/**
 * 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();
}

성능을 테스트하기 위해 다음 코드를 실행할 수 있습니다.

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

나는 당신의 대부분이 내가 한 일을 이해할 것이라고 확신하지만, 설명이 필요한 사람이 적어도 한 명있을 것입니다.

알고리즘 :

  • Math.random()함수는 소수점 이하 자릿수 (예 :) 뒤에 16 자리의 0과 1 사이의 10 진수를 반환합니다 0.4363923368509859.
  • 그런 다음이 숫자를 가져 와서 밑 수가 16 인 문자열로 변환합니다 (위의 예에서 0.6fb7687f).
    Math.random().toString(16).
  • 그런 다음 0.접두사 ( 0.6fb7687f=> 6fb7687f)를 잘라 내고 8 개의 16 진 문자로 된 문자열을 얻습니다.
    (Math.random().toString(16).substr(2,8).
  • 때때로 Math.random()함수는 0.4363끝에서 0으로 인해 더 짧은 숫자 (예 :)를 반환 합니다 (위의 예에서 실제로 숫자는 0.4363000000000000). 그렇기 때문에이 문자열 "000000000"(0이 0 인 문자열)에 추가 한 다음 substr()9 개의 문자를 정확하게 만드는 기능으로 잘라냅니다 (오른쪽에 0을 채 웁니다).
  • 정확히 9 개의 0을 추가하는 이유는 Math.random()함수가 정확히 0 또는 1을 반환 할 때 (각각에 대해 1 / 10 ^ 16의 확률) 더 나쁜 경우 시나리오 때문입니다 . 그렇기 때문에 9 개의 0을 추가 ( "0"+"000000000"또는 "1"+"000000000") 한 다음 길이가 8자인 두 번째 색인 (3 번째 문자)에서 잘라 내야했습니다. 나머지 경우에는 0을 추가해도 결과가 잘 리므로 결과에 영향을 미치지 않습니다.
    Math.random().toString(16)+"000000000").substr(2,8).

어셈블리 :

  • GUID의 형식은 다음과 같습니다 XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • I는 4 개, 2 종 (또는 포맷)으로 나누어 각각의 부분으로 분할 GUID : XXXXXXXX-XXXX-XXXX.
  • 이제이 두 가지 유형을 사용하여 GUID를 빌드하여 다음과 같이 4 조각으로 GUID를 조립합니다 XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • 이 두 가지 유형을 구별하기 위해 쌍 생성자 함수에 플래그 매개 변수를 추가했습니다 _p8(s).이 s매개 변수는 함수에 대시를 추가할지 여부를 알려줍니다.
  • 결국 다음 체인을 사용하여 GUID를 빌드 _p8() + _p8(true) + _p8(true) + _p8()하고 반환합니다.

내 블로그에서이 게시물에 링크

즐겨! :-)


13
이 구현이 잘못되었습니다. GUID의 특정 문자에는 특별한 처리가 필요합니다 (예 : 13 번째 숫자는 4 여야 함).
JLRishe

67

다음은 Chrome의 충돌에 대한 해결 방법과 함께 가장 많이 투표 된 답변 의 조합입니다 .

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);
        });
    };

테스트하려는 경우 jsbin에서 .


3
첫 번째 버전 인`window.crypto.getRandomValues , does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` 버전은 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
humanandANDpeace

66

다음은 ASCII 안전 GUID와 같은 고유 식별자를 생성하기위한 완전히 호환되지 않지만 성능이 뛰어난 구현입니다.

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

RFC 호환 GUID보다 짧고 고유 한 UID를 생성하는 26 개의 [a-z0-9] 문자를 생성합니다. 사람의 가독성이 중요한 경우 대시를 사소하게 추가 할 수 있습니다.

다음은이 함수의 사용법 예제와 타이밍 및이 질문의 다른 답변 중 일부입니다. 타이밍은 Chrome m25에서 각각 천만 번 반복하여 수행되었습니다.

>>> 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

타이밍 코드는 다음과 같습니다.

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

62

다음 은 https://gist.github.com/982883의 사용자 jed 가 작성한 주석의 2011 년 10 월 9 일자 솔루션입니다 .

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

이것은 현재 최고 등급의 답변 과 동일한 목표를 달성 하지만, 강제, 재귀 및 지수 표기법을 활용하여 바이트 수가 50 바이트 이상 줄어 듭니다. 어떻게 작동하는지 궁금한 사람들을 위해 이전 버전의 함수에 주석이 달린 형식이 있습니다.

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

에서 SAGI shkedy 기술 블로그입니다 :

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;
}

ActiveX 컨트롤을 사용하는 다른 방법이 있지만 이러한 방법을 피하십시오!

편집 : GUID 생성기가 고유 키를 보장 할 수 없다는 것을 지적 할 가치가 있다고 생각했습니다 ( wikipedia 기사 확인) ). 충돌 가능성이 항상 있습니다. GUID는 단순히 충돌의 변화를 거의 없앨 수 있도록 충분히 큰 키 공간을 제공합니다.


8
이것은 기술적 인 의미에서 GUID가 아닙니다. 독창성을 보장 할 수는 없기 때문입니다. 응용 프로그램에 따라 중요하거나 중요하지 않을 수 있습니다.
Stephen Deken

2
성능에 대한 간단한 참고 사항. 이 솔루션은 단일 결과를 얻기 위해 총 36 개의 문자열을 만듭니다. 성능이 중요한 경우가 권장하는 배열을 생성하고 가입을 고려 : tinyurl.com/y37xtx 더 많은 연구가 중요하지 않을 수 있습니다 나타냅니다 YMMV 그래서 : tinyurl.com/3l7945
브랜든 DuRette

2
고유성에 대해서는 버전 1, 3 및 5 UUID가 버전 4와 달리 결정 론적이라는 점에 주목할 가치가 있습니다. 이 UUID 생성기 (v1의 노드 ID, v3 및 v5의 네임 스페이스 및 이름)에 대한 입력이 고유해야하는 경우 결과 UUID는 고유합니다. 이론적으로, 어쨌든.
broofa

41

node-uuid ( https://github.com/kelektiv/node-uuid )를

간단하고 빠른 생성 RFC4122 UUIDS

풍모:

  • RFC4122 버전 1 또는 버전 4 UUID 생성
  • node.js 및 브라우저에서 실행됩니다.
  • 지원 플랫폼에서 암호화 적으로 강력한 랜덤 # 생성.
  • 작은 발자국 (작은 것을 원하십니까? 이것을 확인하십시오! )

NPM을 사용하여 설치 :

npm install uuid

또는 브라우저를 통한 UUID 사용

원시 파일 다운로드 (uuid v1) : https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js 원시 파일 다운로드 (uuid v4) : https://raw.githubusercontent.com/kelektiv/node -uuid / master / v4.js


더 작은 것을 원하십니까? 이것을 확인하십시오 : https://gist.github.com/jed/982883


용법:

// 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);
    });
};

편집하다:

이 기능을 사용하고있는 프로젝트를 다시 방문하여 자세한 정보를 싫어했습니다. 그러나 적절한 무작위성이 필요했습니다.

버퍼에서 니블 크기의 창을 추출하는 Briguy37의 답변과 일부 비트 연산자를 기반으로 한 버전입니다.

Java UUID로 비 규격 UUID를 구문 분석하는 데 문제가 있었으므로 RFC 유형 4 (임의) 스키마를 준수해야합니다.


31

이 글타래에서 최고의 답변을 조합 한 간단한 자바 스크립트 모듈.

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());

용법:

Guid.newGuid ()

"c6c2d12f-d76b-5739-e551-07e6de5b0807"

Guid.empty

"00000000-0000-0000-0000-000000000000"


1
무슨 일 괴롭히는 모든 답은 보인다 있다는 것입니다 확인 자바 스크립트를 저장하기 위해 GUIDA와 string. 귀하의 답변은 적어도를 사용하여 훨씬 더 효율적인 스토리지를 처리합니다 Uint16Array. 이 toString함수는 JavaScript에서 이진 표현을 사용해야합니다.object
Sebastian

이 코드에 의해 생성 된이 UUID는 RFC (약하지만 RFC 호환)이거나 RFC와 호환되지 않는 (_cryptoGuid)입니다. 전자는 현재 RNG가 불량한 것으로 알려진 Math.random ()을 사용합니다. 후자는 버전 및 변형 필드를 설정하지 못했습니다.
broofa

@broofa-강력 하고 RFC를 준수 하기 위해 무엇을 제안 하시겠습니까? _cryptoGuid가 RFC를 준수하지 않는 이유는 무엇입니까?
Matt

@Matt _cryptoGuid ()는 128 비트를 모두 임의로 설정하므로 RFC에 설명 된대로 버전 및 변형 필드를 설정하지 않습니다. 강력하고 호환되는 구현에 대해서는 위의 투표에서 crypto.getRandomValues ​​()를 사용하는 uuidv4 ()의 대체 구현을 참조하십시오.
broofa

29

이것은 의사 난수로 만든 버전 4 UUID를 만듭니다.

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('');
}

다음은 생성 된 UUID 샘플입니다.

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

28

글쎄, 이것은 이미 많은 대답을 가지고 있지만 불행히도 무리에 "진정한"임의가 없습니다. 아래 버전은 broofa의 답변을 수정 한 것이지만, 가능한 경우 암호화 라이브러리를 사용하는 "진정한"임의 함수와 대체로 Alea () 함수를 포함하도록 업데이트되었습니다.

  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의 JavaScript 프로젝트-https: //github.com/LiosK/UUID.js

UUID.js JavaScript를위한 RFC 호환 UUID 생성기.

RFC 4122 http://www.ietf.org/rfc/rfc4122.txt를 참조하십시오 .

기능 RFC 4122 호환 UUID를 생성합니다.

버전 4 UUID (임의의 UUID) 및 버전 1 UUID (시간 기반 UUID)를 사용할 수 있습니다.

UUID 객체는 UUID 필드에 대한 액세스를 포함하여 UUID에 대한 다양한 액세스를 허용합니다.

JavaScript의 낮은 타임 스탬프 해상도는 난수로 보상됩니다.


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의 답변을 이해하고 싶었으므로 그것을 확장하고 의견을 추가했습니다.

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);
        }
    );
};

자세한 설명 감사합니다! 8과 11 사이에 갇힌 니블은 특히 설명이 도움이됩니다.
Egor Litvinchuk

15

여기에 추가로 내 자신의 UUID / GUID 생성기를 조정 했습니다 .

다음 Kybos를 사용 하고 있습니다. 조금 더 암호화 소리로 난수 생성기를.

아래는 baagoe.com의 Mash 및 Kybos 메소드가 제외 된 스크립트입니다.

//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

속도를 고려한 rfc4122 버전 4 호환 솔루션을 원하는 경우 (Math.random ()을 거의 호출하지 않음) :

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() );

위의 기능은 속도와 임의성 사이의 균형이 맞아야합니다.


13

ES6 샘플

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

12

더 좋은 방법 :

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
 }

최소화 :

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

나는 오래된 질문입니다. 완벽을 기하기 위해 환경이 SharePoint 인 경우 새 ms를 만드는 SP.Guid.newGuid( msdn link ) 라는 유틸리티 기능이 있습니다. 이 기능은 sp.init.js 파일에 있습니다. 이 함수를 다시 작성하면 (다른 개인 함수에서 다른 종속성을 제거하기 위해) 다음과 같습니다

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

이 날짜는 날짜를 기준으로하며 고유성을 보장하기 위해 임의 접미사를 추가합니다. CSS 식별자에 적합합니다. 항상 같은 것을 반환하고 해킹하기 쉽습니다.

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

지원되는 브라우저 (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome)에서 사용 crypto.getRandomValues(a)하는 간단한 코드입니다 . 충돌을 일으킬 수 있으므로 사용을 피하십시오 (예 : Muxa 의 실제 상황에서 4000 생성 된 UUID에 대해 20 개의 충돌 ).Math.random()

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);
}

노트:

  • 속도가 아닌 코드 가독성을 위해 최적화되어 초당 수백 uuid에 적합합니다. http://jsbin.com/fuwigo/1을 사용하여 랩톱의 Chromium에서 초당 약 10000 uuid () 생성 을 성능을 측정합니다.
  • 코드 가독성을 단순화하기 때문에 "y"에 8 만 사용합니다 (y는 8, 9, A 또는 B 일 수 있음).

11

특정 형식이 아닌 임의의 128 비트 문자열이 필요한 경우 다음을 사용할 수 있습니다.

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

다음과 같은 것을 반환합니다 2350143528-4164020887-938913176-2513998651.


BTW, 왜 문자가 아닌 숫자 만 생성합니까? 훨씬 덜 안전
vsync

1
다음과 같이 문자 (문자)를 추가 할 수도 있습니다.Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
magikMaker

11

단지 두 개의 돌연변이를 가진 또 다른 더 읽기 쉬운 변형.

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, '-');
}

대부분의 js 개발자는 웹 개발자이며 우리는 비트 연산자가 우리가 개발하는 대부분의 시간을 사용하지 않기 때문에 비트 연산자가 무엇을하는지 이해하지 못합니다. 실제로 나는 그들 중 어느 것도 필요하지 않았으며 97 년부터 js 개발자입니다. 따라서 귀하의 예제 코드는 여전히 일반적인 웹 개발자가 읽을 수 없습니다. 말할 것도없이 단일 문자 변수 이름을 사용한다는 것은 말할 것도없이 훨씬 더 복잡합니다. 아마도 Clean Code를 읽을 수 있습니다. amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/…
inf3rno

@ inf3rno는 그를 강타하지 않습니다.이 스레드에서 제안 된 모든 솔루션은 암호가 있지만 질문은 일종의 한 줄짜리를 갖는 것을 고려하면 정답입니다. 그것이 한 라이너가 비밀스러운 것입니다. 그들은 일반 개발자가 읽을 수는 없지만 간단한 선행 설명이 수행되는 화면 공간을 절약합니다. 결과적으로 "읽을 수있는 코드"에있는 경우 훨씬 더 읽기 쉽습니다.
tatsu

랜덤! = 고유
1529413

@ user1529413 예. 고유성에는 색인이 필요합니다.
소집

이것은 UUID를 16 바이트 (128 비트) 값으로 작성하기 때문에 직렬화 된 읽기 쉬운 형식이 아니기 때문에 내가 가장 좋아하는 대답입니다. 문자열 항목을 삭제하고 임의의 128 비트의 올바른 비트를 설정하는 것이 간단합니다. 이는 모든 uuidv4가 필요합니다. 더 짧은 URL의 경우 base64로, 웹 어셈블리로 다시 전달하고, 문자열보다 적은 메모리 공간에 저장하고, 4096 크기의 버퍼로 만들고, 256 개의 uuid를 넣고, 브라우저 db에 저장하는 등 훨씬 더 좋습니다. 처음부터 모든 것을 소문자 16 진수로 인코딩 된 긴 문자열로 만드는 것보다
Qaribou의 Josh

8

uuid 패키지를 사용하여 버전 1, 3, 4 및 5 UUID를 지원합니다 .

yarn add uuid

그리고:

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

완전히 지정된 옵션을 사용하여 수행 할 수도 있습니다.

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'

자세한 정보는 여기 에서 npm 페이지를 방문 하십시오.


6

이를 위해 자신의 물건을 채찍질하는 대신 둘 이상의 제공자가 유지 관리하는 잘 테스트 된 코드를 사용하는 것이 중요합니다. 이것은 X 브라우저에서 작동하지만 Y의 특이성을 고려하지 않는 가능한 가장 짧은 영리한 버전보다 가장 안정적인 코드를 선호하는 곳 중 하나입니다. 일부 사용자의 경우 개인적 으로 bower가 활성화 된 https://github.com/aurigadl/uuid-js 에서 uuid-js를 사용하므로 쉽게 업데이트 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.