Skip to content
Create a gist now

Instantly share code, notes, and snippets.

generate random UUIDs

UUID

Returns a random v4 UUID of the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, where each x is replaced with a random hexadecimal digit from 0 to f, and y is replaced with a random hexadecimal digit from 8 to b.

There's also @LeverOne's approach using iteration, which is one byte shorter.

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
)
}
function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 Jed Schmidt <http://jed.is>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "UUID",
"description": "Generates random UUIDs",
"keywords": [
"UUID",
"ID",
"random"
]
}
@subzey
subzey commented Aug 12, 2011

We can use coercion and exponential notation to get template string and save 7 bytes:
function(){return(""+1e7+-1e3+-4e3+-8e3+-1e11).replace(/1|0/g,function(){return(0|Math.random()*16).toString(16)})}

@jed
Owner
jed commented Aug 13, 2011

subzey, you are a genius. fixing and annotating now.

@jed
Owner
jed commented Aug 13, 2011

you also inspired me to cut 10 more bytes out:

function b(a){return a?(0|Math.random()*16).toString(16):(""+1e7+-1e3+-4e3+-8e3+-1e11).replace(/1|0/g,b)}
@jed
Owner
jed commented Aug 13, 2011
(0|Math.random()*16).toString(16)

can also be trimmed 4 bytes to

Math.random().toString(16)[2]

if you don't care about IE... thoughts?

@subzey
subzey commented Aug 13, 2011

@jed, Math.random() may return 0, so Math.random().toString(16)[2] may return undefined.

Also, isn't setting name of function affects the outer scope?

@jed
Owner
jed commented Aug 13, 2011

well, with the chance of Math.random returning a zero 1 in 2<<61, seems like the definition of an edge case. more likely that IE barfs on it.

also, we're allowing named functions because we assume that they'll be assigned externally.

@subzey
subzey commented Aug 13, 2011

@jed, thanks for your clarification about function names, I didn't know that

@jed
Owner
jed commented Aug 15, 2011

@subzey, i hope you use this knowledge to bring us some awesome new stuff.

@LeverOne
LeverOne commented Oct 6, 2011

""+1e7+-1e3+-4e3+-8e3+-1e11 --> [1e7]+-1e3+-4e3+-8e3+-1e11
it's а flaw of many of you.

@subzey
subzey commented Oct 7, 2011

@LeverOne, perfect! Thanks

@jed
Owner
jed commented Oct 7, 2011

wow, that's crazy. good work @LeverOne.

@fgnass
fgnass commented Oct 7, 2011

What about replacing /1|0/ with /\d/?

@jed
Owner
jed commented Oct 7, 2011

the 4 is hardcoded according to the spec, and the 8 is a bit of a hack... technically it should be anything from 8 to b. so replacing those would make it less compliant.

@fgnass
fgnass commented Oct 7, 2011

Ah I see, I missed that.

@jed
Owner
jed commented Oct 7, 2011

i wonder if we finally have enough bytes to make it compliant, such that the 8 can be 8, 9, a, or b...

@subzey
subzey commented Oct 7, 2011

It is enough already :)

function c(a,b){return a?(~~b+0|Math.random()*16>>b/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/1|0|(8)/g,c)}
@subzey
subzey commented Oct 7, 2011

Or this, shorter:

function c(a,b){return a?(b|Math.random()*16>>b/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/1|0|(8)/g,c)}
@jed
Owner
jed commented Oct 7, 2011

thanks again, @subzey. updated.

@broofa
broofa commented Oct 7, 2011

Line 20 of annotated.js should be 'c', not 'b'.

BTW, you're all insane. I love it! :)

@jed
Owner
jed commented Oct 7, 2011

good catch! for those not in the know, @broofa is a celebrity in the world of UUIDs: https://github.com/broofa/node-uuid

@tsaniel
tsaniel commented Oct 9, 2011

Maybe save 4 bytes...?
```function c(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[108]/g,c)}

@jed
Owner
jed commented Oct 9, 2011

what the... how on earth does this work?

@tsaniel
tsaniel commented Oct 9, 2011

There are three possible values 0,1,8 for a.

For case 0: 0^Math.random()*16>>0/4, >>0/4 is actually >>0, just works as Math.floor.
The 0^ here does nothing.

For case 1: 1^Math.random()*16>>1/4, >>1/4 is still >>0.
Although 1^ here toggles the least significant bit, we can still use it to generate random numbers 0-15.

For case 8: 8^Math.random()*16>>8/4, >>8/4 turns out >>2.
The maximum number of Math.random()*16 in binary form is 1111, that means the range is 0000-1111.
By right shifting 2 bits, the maximum number of Math.random()*16>>2 is 0011, and the range, 0000-0011. What it does here is to generate random numbers 0-3.
Finally, because the most significant bit is always 0, 8^ is actually 8|, it is to ensure the range starts from 8. And now we get 8 + {0, 1, 2, 3}.

@jed
Owner
jed commented Oct 9, 2011

incredible work, @tsaniel!

@jed
Owner
jed commented Oct 9, 2011

it's amazing how this gist has evolved, from

function(){return"00000000-0000-4000-8000-000000000000".replace(/0/g,function(){return(0|Math.random()*16).toString(16)})}

to

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

while hitting all the greatest hits: recursion, coercion of a number into a string through an array (!), operator repurposing...

@tsaniel
tsaniel commented Oct 9, 2011

I love those tricks, especially the string coercion with array, though i love bitwise tricks.
By the way, i am still thinking if we can shorten /[018]/...

@atk
atk commented Oct 9, 2011

@tsaniel - no way, the other way round would be /[^4-]/, which is just as long.

@tsaniel
tsaniel commented Oct 9, 2011

@atk: That's true. I mean if we can do something to use /\d/ instead.

@atk
atk commented Oct 9, 2011

...which would require that the 4 will be left alone and enlarge the equation probably more than the 3 letters we saved.

@tsaniel
tsaniel commented Oct 9, 2011

Maybe that's the end.

@atk
atk commented Oct 9, 2011

I fear it is.

@subzey
subzey commented Oct 11, 2011

Once again, excellent work, @tsaniel!

Sorry for my late comment, my mobile browser doesn't work well with github

@LeverOne

Recursion & coercion vs. loop & math: https://gist.github.com/1308368

@jed
Owner
jed commented Oct 24, 2011

just when you thought it couldn't get any shorter, @LeverOne sheds a byte. good job!

@tsaniel
tsaniel commented Oct 24, 2011

@LeverOne is my hero.

@kalupa
kalupa commented Jun 20, 2013

damnit jed, i keep finding you everywhere. thanks for this!

@jussi-kalliokoski

In Firefox you could use the single statement function body to shorten it a few bits still:

function b(a)a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)
@jussi-kalliokoski

Shorter yet (cheats, ES6, and works only in Firefox!!!), and less leaky:

function()([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,a=>(a^Math.random()*16>>a/4).toString(16))
@jussi-kalliokoski

Hah, since I already used ES6 and there are no variable assignments, might as well go all the way and avoid Firefox-only stuff:

()=>([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,a=>(a^Math.random()*16>>a/4).toString(16))
@jameswyse

This is awesome!

Here's a benchmark vs node-uuid: http://jsperf.com/node-uuid-performance/11

@ronkorving

I was so rooting for Crazy Gist to win that one :(

@thelinuxlich

Is this relatively safe to generate UUIDs simultaneously between many clients?

@coolaj86
coolaj86 commented Nov 8, 2015

Make it secure at the cost of just a few bytes by replacing Math.random() * 16:

browser

crypto.getRandomValues(new Uint8Array(1))[0] % 16

function b(
  a                  // placeholder
){
  return a           // if the placeholder was passed, return
    ? (              // a random number from 0 to 15
      a ^            // unless b is 8,
      crypto.getRandomValues(new Uint8Array(1))[0]  // 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.js

crypto.randomBytes(1)[0] % 16

function b(
  a                  // placeholder
){
  return a           // if the placeholder was passed, return
    ? (              // a random number from 0 to 15
      a ^            // unless b is 8,
      crypto.randomBytes(1)[0]  // 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
      )
}
@dalanmiller

@coolaj89 I don't have crypto.randomBytes in Chrome 46.0.2490.80 but there is crypto.getRandomValues

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.