JavaScript에서 전역적으로 고유한 식별자를 만들려고 합니다. 모든 브라우저에서 어떤 루틴을 사용할 수 있는지, 내장된 난수 생성기가 얼마나 "임의"이고 시드되었는지 등을 잘 모르겠습니다.
GUID/UUID는 32자 이상이어야 하며 전달할 때 문제가 발생하지 않도록 ASCII 범위에 있어야 합니다.
질문자 :Community Wiki
JavaScript에서 전역적으로 고유한 식별자를 만들려고 합니다. 모든 브라우저에서 어떤 루틴을 사용할 수 있는지, 내장된 난수 생성기가 얼마나 "임의"이고 시드되었는지 등을 잘 모르겠습니다.
GUID/UUID는 32자 이상이어야 하며 전달할 때 문제가 발생하지 않도록 ASCII 범위에 있어야 합니다.
RFC4122 버전 4 호환 솔루션의 경우 이 단일 라이너(ish) 솔루션은 내가 생각해낼 수 있는 가장 컴팩트한 솔루션입니다.
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()
Math.random()
은 고품질 RNG라고 보장 되지 않습니다. 자세한 내용은 Math.random()에 대한 Adam Hyland의 뛰어난 글을 참조하십시오. 보다 강력한 솔루션을 위해 고품질 RNG API를 사용 하는 uuid 모듈 사용을 고려하십시오.
업데이트, 2015-08-26 : 부수적으로 이 요지 는 특정 충돌 확률에 도달하기 전에 생성할 수 있는 ID 수를 결정하는 방법을 설명합니다. 예를 들어, 3.26x10 15 버전 4 RFC4122 UUID를 사용하면 100만 분의 1의 충돌 가능성이 있습니다.
업데이트, 2017-06-28 : Chrome, Firefox 및 Safari에서 Math.random
PRNG 품질 상태에 대해 논의하는 Chrome 개발자의 좋은 기사입니다. tl;dr - 2015년 말 현재 "상당히 좋지만" 암호화 품질이 아닙니다. crypto
API 및 내가 인정할 수 없는 약간의 JavaScript 마법사 를 사용하는 위 솔루션의 업데이트된 버전이 있습니다.
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 : JavaScript 언어의 일부로 표준 uuid
모듈에 대한 제안이 있습니다.
RFC 4122 에 따라 GUID(Globally Unique IDentifier)라고도 하는 UUID(Universally Unique IDentifier)는 특정 고유성 보장을 제공하도록 설계된 식별자입니다.
몇 줄의 JavaScript 코드로 RFC 호환 UUID를 구현할 수 있지만(예: 아래 @broofa의 답변 참조) 몇 가지 일반적인 함정이 있습니다.
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
" 형식이어야 합니다. 여기서 x는 [0-9, af] 중 하나입니다. M 은 [1-5] 중 하나이고 N 은 [8, 9, a 또는 b]Math.random
)따라서 프로덕션 환경을 위한 코드를 작성하는 개발자는 uuid 모듈과 같이 엄격하고 잘 유지되는 구현을 사용하는 것이 좋습니다.
나는 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 = ((typeof performance !== 'undefined') && 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); }); } var onClick = function(){ document.getElementById('uuid').textContent = generateUUID(); } onClick();
#uuid { font-family: monospace; font-size: 1.5em; }
<p id="uuid"></p> <button id="generateUUID" onclick="onClick();">Generate UUID</button>
const generateUUID = () => { let d = new Date().getTime(), d2 = (performance && performance.now && (performance.now() * 1000)) || 0; return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { let r = Math.random() * 16; if (d > 0) { r = (d + r) % 16 | 0; d = Math.floor(d / 16); } else { r = (d2 + r) % 16 | 0; d2 = Math.floor(d2 / 16); } return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16); }); }; const onClick = (e) => document.getElementById('uuid').textContent = generateUUID(); document.getElementById('generateUUID').addEventListener('click', onClick); onClick();
#uuid { font-family: monospace; font-size: 1.5em; }
<p id="uuid"></p> <button id="generateUUID">Generate UUID</button>
broofa의 대답 은 정말 매끄럽습니다. 인상적으로 영리하고 정말... RFC4122를 준수하고 다소 읽기 쉽고 컴팩트합니다. 엄청난!
그러나 그 정규식, 그 많은 replace()
콜백, toString()
및 Math.random()
함수 호출(결과의 4비트만 사용하고 나머지는 낭비함)을 보고 있다면 시작할 수 있습니다. 성능에 대해 궁금합니다. generateQuickGUID
사용하여 일반 GUID 속도에 대한 RFC를 폐기하기로 결정했습니다.
그러나 속도 와 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번째 최적화 반복을 통해 가장 인기 있는 답변을 12배 이상, 허용된 답변을 9배 이상, 빠른 비준수 답변을 2-3배 이상 앞질렀습니다 . 그리고 나는 여전히 RFC 4122를 준수합니다.
방법에 관심이 있으십니까? 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
를 임의의 데이터로 대체하고(RFC 사양에 10
-
또는 4
문자와 일치하지 않으므로 처리할 필요가 없습니다. 그들과 함께. 아주 매끄럽습니다.
가장 먼저 알아야 할 것은 정규 표현식과 마찬가지로 함수 호출이 비싸다는 것입니다(그는 1개만 사용하지만 각 일치에 대해 하나씩 32개의 콜백이 있으며 32개의 콜백 각각에서 Math.random() 및 v를 호출합니다. toString(16)).
성능을 향한 첫 번째 단계는 RegEx와 해당 콜백 함수를 제거하고 대신 간단한 루프를 사용하는 것입니다. 이것은 broofa가 처리하지 않은 -
및 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())
한 번에 16비트를 처리하는 e6()을 시도했지만 여전히 256개 요소의 LUT 를 사용하고 있으며, 최적화 결과가 감소하는 것으로 나타났습니다. 반복 횟수는 적었지만 처리 증가로 인해 내부 로직이 복잡해졌으며 데스크톱에서는 동일하게 수행되었으며 모바일에서는 ~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())
모듈화: http://jcward.com/UUID.js - UUID.generate()
재미있는 점은 16바이트의 임의 데이터를 생성하는 것이 쉬운 부분이라는 것입니다. 전체 트릭은 RFC 준수를 사용하여 문자열 형식으로 표현하는 것이며 16바이트의 임의 데이터, 롤링되지 않은 루프 및 조회 테이블로 가장 밀접하게 수행됩니다.
내 논리가 정확하기를 바랍니다. 이런 종류의 지루한 작업에서 실수를 하는 것은 매우 쉽습니다. 그러나 출력은 나에게 좋아 보입니다. 코드 최적화를 통해 이 미친 라이드를 즐기셨기를 바랍니다!
참고로 제 주요 목표는 잠재적인 최적화 전략을 보여주고 가르치는 것이었습니다. 다른 답변은 좋은 UUID를 생성하는 데 중요한 충돌 및 진정한 난수와 같은 중요한 주제를 다룹니다.
사용하다:
let uniqueId = Date.now().toString(36) + Math.random().toString(36).substring(2);
document.getElementById("unique").innerHTML = Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);
<div id="unique"> </div>
ID가 1밀리초 이상 간격으로 생성되면 100% 고유합니다.
더 짧은 간격으로 두 개의 ID가 생성되고 random 메서드가 실제로 임의적이라고 가정하면 전역적으로 고유할 가능성이 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('-');
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('-'); document.getElementById("unique").innerHTML = guid;
<div id="unique"> </div>
위의 코드는 의도를 따르지만 RFC의 문자는 아닙니다. 다른 불일치 중에서 몇 개의 임의의 숫자가 짧습니다. (필요한 경우 임의의 숫자를 더 추가하세요.) 장점은 이것이 정말 빠르다는 것입니다. :) 여기에서 GUID의 유효성을 테스트할 수 있습니다.
다음은 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; }
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
형식의 가장 빠른 GUID와 유사한 문자열 생성기 방법입니다. 표준 호환 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 사이의 십진수를 반환합니다(예: 0.4363923368509859
).0.6fb7687f
). Math.random().toString(16)
.0.
접두사( 0.6fb7687f
=> 6fb7687f
)를 잘라내고 8개의 16진수 문자로 된 문자열을 얻습니다. (Math.random().toString(16).substr(2,8)
.Math.random()
함수는 끝에 0으로 인해 더 짧은 숫자(예: 0.4363
)를 반환합니다(위의 예에서 실제로 숫자는 0.4363000000000000
). 그렇기 때문에 이 문자열 "000000000"
(9개의 0이 있는 문자열)을 추가한 다음 substr()
함수로 잘라서 정확히 9개의 문자로 만듭니다(오른쪽에 0 채우기).Math.random()
함수가 정확히 0 또는 1(각각 1/10^16의 확률)을 반환하는 최악의 시나리오 때문입니다. 그렇기 때문에 여기에 9개의 0을 추가해야 했습니다( "0"+"000000000"
또는 "1"+"000000000"
). 그런 다음 길이가 8자인 두 번째 인덱스(세 번째 문자)에서 잘라야 했습니다. 나머지 경우에는 0을 추가해도 결과가 잘려나가기 때문에 결과에 해를 끼치지 않습니다. Math.random().toString(16)+"000000000").substr(2,8)
.어셈블리:
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
입니다.XXXXXXXX
및 -XXXX-XXXX
.XXXXXXXX
-XXXX-XXXX
-XXXX-XXXX
XXXXXXXX
._p8(s)
플래그 매개변수를 추가했습니다. s
매개변수는 대시를 추가할지 여부를 함수에 알려줍니다._p8() + _p8(true) + _p8(true) + _p8()
체이닝을 사용하여 GUID를 빌드하고 반환합니다.즐기다! :-)
다음은 ASCII 안전 GUID와 유사한 고유 식별자를 생성하기 위한 완전히 호환되지 않지만 매우 성능이 뛰어난 구현입니다.
function generateQuickGuid() { return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); }
26개의 [a-z0-9]자를 생성하여 RFC 호환 GUID보다 짧고 고유한 UID를 생성합니다. 사람의 가독성이 중요한 경우 대시를 간단하게 추가할 수 있습니다.
다음은 이 기능의 사용 예와 타이밍과 이 질문의 다른 답변입니다. 타이밍은 Chrome m25에서 각각 1천만 번 반복하여 수행되었습니다.
>>> 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');
다음은 Chrome 충돌에 대한 해결 방법과 함께 가장 많이 투표된 답변 의 조합입니다.
generateGUID = (typeof(window.crypto) != 'undefined' && typeof(window.crypto.getRandomValues) != 'undefined') ? function() { // If we have a cryptographically secure PRNG, use that // https://stackoverflow.com/questions/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 // https://stackoverflow.com/questions/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에 있습니다.
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는 충돌의 변화를 거의 0으로 줄이기 위해 충분히 큰 키 유니버스를 제공합니다.
다음은 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 ) }
node-uuid 를 사용할 수 있습니다. RFC4122 UUIDS의 간단하고 빠른 생성을 제공합니다.
특징:
NPM을 사용하여 설치:
npm install uuid
또는 브라우저를 통해 uuid 사용:
Raw 파일 다운로드(uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Raw 파일 다운로드(uuid v4): https://raw.githubusercontent.com/kelektiv/node -uuid/마스터/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'
ECMAScript 2015(ES6):
import uuid from 'uuid/v4'; const id = uuid();
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(임의) 스키마를 준수해야 합니다.
이렇게 하면 버전 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
이 질문에 대한 베스트 답변의 조합으로 간단한 JavaScript 모듈.
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"
아래 버전은 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); }); };
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의 낮은 타임스탬프 해상도는 난수로 보상됩니다.
// 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('-');
속도를 고려한 RFC 4122 버전 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() );
위의 기능은 속도와 임의성 간에 적절한 균형을 유지해야 합니다.
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); } ); };
여기에 몇 가지 추가 기능을 사용하여 자체 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));
ES6 샘플
const guid=()=> { const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`; }
특정 형식이 없는 임의의 128비트 문자열만 필요한 경우 다음을 사용할 수 있습니다.
function uuid() { return crypto.getRandomValues(new Uint32Array(4)).join('-'); }
2350143528-4164020887-938913176-2513998651
과 같은 값을 반환합니다.
기본 URL.createObjectURL
이 UUID를 생성합니다. 이것을 활용할 수 있습니다.
function uuid() { const url = URL.createObjectURL(new Blob()) const [id] = url.toString().split('/').reverse() URL.revokeObjectURL(url) return id }
단지 두 개의 돌연변이가 있는 더 읽기 쉬운 또 다른 변종입니다.
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, '-'); }
더 나은 방법:
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, ? // generate 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}
환경이 SharePoint인 경우 SP.Guid.newGuid
( 새 GUID를 생성하는 MSDN 링크) 라는 유틸리티 함수가 있습니다. 이 함수는 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; };
다음은 지원되는 브라우저 (Internet Explorer 11+, iOS 7+, Firefox 21+, Chrome, Android Chrome)에서 crypto.getRandomValues(a)
를 사용하는 간단한 코드입니다.
그것은 사용하는 것을 피한다 Math.random()
즉, (의한 실제 상황에서, 예를 들어 4000 생성 된 UUID를 20 개 충돌을 충돌을 일으킬 수 있기 때문에, Muxa ).
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); }
노트:
이것은 날짜를 기반으로 하며 고유성을 "보장"하기 위해 임의의 접미사를 추가합니다.
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; };
좋아, 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 페이지를 방문하십시오.
출처 : 여기를 클릭하세요
출처 : http:www.stackoverflow.com/questions/105034/how-to-create-a-guid-uuid
Python에서 중첩 디렉토리를 어떻게 안전하게 만들 수 있습니까? (0) | 2021.09.30 |
---|---|
jQuery에서 확인란이 선택되어 있는지 어떻게 확인합니까? (0) | 2021.09.30 |
정적 메서드와 클래스 메서드의 차이점 (0) | 2021.09.30 |
요소를 가로로 가운데에 맞추는 방법 (0) | 2021.09.30 |
로컬 리포지토리 분기를 원격 리포지토리 HEAD와 동일하게 재설정 (0) | 2021.09.30 |