2209
votes

I want a 5 character string composed of characters picked randomly from the set [a-zA-Z0-9].

What's the best way to do this with JavaScript?

30
Warning: None of the answers have a true-random result! They are only pseudo-random. When using random strings for protection or security, don't use any of them!!! Try one of these api's: random.orgRon van der Heijden
Math.random().toString(36).replace(/[^a-z]+/g, '')Muaz Khan
Please put the solution in a solution.chryss
Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);Friedrich
Note HTML5 webcrypto randomness API provides real randomness.mikemaccana

30 Answers

2992
votes

I think this will work for you:

function makeid(length) {
    var result           = '';
    var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var charactersLength = characters.length;
    for ( var i = 0; i < length; i++ ) {
      result += characters.charAt(Math.floor(Math.random() * 
 charactersLength));
   }
   return result;
}

console.log(makeid(5));
2706
votes

let r = Math.random().toString(36).substring(7);
console.log("random", r);

Note: The above algorithm has the following weaknesses:

  • It will generate anywhere between 0 and 6 characters due to the fact that trailing zeros get removed when stringifying floating points.
  • It depends deeply on the algorithm used to stringify floating point numbers, which is horrifically complex. (See the paper "How to Print Floating-Point Numbers Accurately".)
  • Math.random() may produce predictable ("random-looking" but not really random) output depending on the implementation. The resulting string is not suitable when you need to guarantee uniqueness or unpredictability.
  • Even if it produced 6 uniformly random, unpredictable characters, you can expect to see a duplicate after generating only about 50,000 strings, due to the birthday paradox. (sqrt(36^6) = 46656)
653
votes

Math.random is bad for this kind of thing

Option 1

If you're able to do this server-side, just use the crypto module -

var crypto = require("crypto");
var id = crypto.randomBytes(20).toString('hex');

// "bb5dc8842ca31d4603d6aa11448d1654"

The resulting string will be twice as long as the random bytes you generate; each byte encoded to hex is 2 characters. 20 bytes will be 40 characters of hex.


Option 2

If you have to do this client-side, perhaps try the uuid module -

var uuid = require("uuid");
var id = uuid.v4();

// "110ec58a-a0f2-4ac4-8393-c866d813b8d1"

Option 3

If you have to do this client-side and you don't have to support old browsers, you can do it without dependencies -

// dec2hex :: Integer -> String
// i.e. 0-255 -> '00'-'ff'
function dec2hex (dec) {
  return dec.toString(16).padStart(2, "0")
}

// generateId :: Integer -> String
function generateId (len) {
  var arr = new Uint8Array((len || 40) / 2)
  window.crypto.getRandomValues(arr)
  return Array.from(arr, dec2hex).join('')
}

console.log(generateId())
// "82defcf324571e70b0521d79cce2bf3fffccd69"

console.log(generateId(20))
// "c1a050a4cd1556948d41"

For more information on crypto.getRandomValues -

The crypto.getRandomValues() method lets you get cryptographically strong random values. The array given as the parameter is filled with random numbers (random in its cryptographic meaning).

Here's a little console example -

> var arr = new Uint8Array(4) # make array of 4 bytes (values 0-255)
> arr
Uint8Array(4) [ 0, 0, 0, 0 ]

> window.crypto
Crypto { subtle: SubtleCrypto }

> window.crypto.getRandomValues()
TypeError: Crypto.getRandomValues requires at least 1 argument, but only 0 were passed

> window.crypto.getRandomValues(arr)
Uint8Array(4) [ 235, 229, 94, 228 ]

For IE11 support you can use -

(window.crypto || window.msCrypto).getRandomValues(arr)

For browser coverage see https://caniuse.com/#feat=getrandomvalues

210
votes

Short, easy and reliable

Returns exactly 5 random characters, as opposed to some of the top rated answers found here.

Math.random().toString(36).substr(2, 5);
171
votes

Here's an improvement on doubletap's excellent answer. The original has two drawbacks which are addressed here:

First, as others have mentioned, it has a small probability of producing short strings or even an empty string (if the random number is 0), which may break your application. Here is a solution:

(Math.random().toString(36)+'00000000000000000').slice(2, N+2)

Second, both the original and the solution above limit the string size N to 16 characters. The following will return a string of size N for any N (but note that using N > 16 will not increase the randomness or decrease the probability of collisions):

Array(N+1).join((Math.random().toString(36)+'00000000000000000').slice(2, 18)).slice(0, N)

Explanation:

  1. Pick a random number in the range [0,1), i.e. between 0 (inclusive) and 1 (exclusive).
  2. Convert the number to a base-36 string, i.e. using characters 0-9 and a-z.
  3. Pad with zeros (solves the first issue).
  4. Slice off the leading '0.' prefix and extra padding zeros.
  5. Repeat the string enough times to have at least N characters in it (by Joining empty strings with the shorter random string used as the delimiter).
  6. Slice exactly N characters from the string.

Further thoughts:

  • This solution does not use uppercase letters, but in almost all cases (no pun intended) it does not matter.
  • The maximum string length at N = 16 in the original answer is measured in Chrome. In Firefox it's N = 11. But as explained, the second solution is about supporting any requested string length, not about adding randomness, so it doesn't make much of a difference.
  • All returned strings have an equal probability of being returned, at least as far as the results returned by Math.random() are evenly distributed (this is not cryptographic-strength randomness, in any case).
  • Not all possible strings of size N may be returned. In the second solution this is obvious (since the smaller string is simply being duplicated), but also in the original answer this is true since in the conversion to base-36 the last few bits may not be part of the original random bits. Specifically, if you look at the result of Math.random().toString(36), you'll notice the last character is not evenly distributed. Again, in almost all cases it does not matter, but we slice the final string from the beginning rather than the end of the random string so that short strings (e.g. N=1) aren't affected.

Update:

Here are a couple other functional-style one-liners I came up with. They differ from the solution above in that:

  • They use an explicit arbitrary alphabet (more generic, and suitable to the original question which asked for both uppercase and lowercase letters).
  • All strings of length N have an equal probability of being returned (i.e. strings contain no repetitions).
  • They are based on a map function, rather than the toString(36) trick, which makes them more straightforward and easy to understand.

So, say your alphabet of choice is

var s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

Then these two are equivalent to each other, so you can pick whichever is more intuitive to you:

Array(N).join().split(',').map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('');

and

Array.apply(null, Array(N)).map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('');

Edit:

I seems like qubyte and Martijn de Milliano came up with solutions similar to the latter (kudos!), which I somehow missed. Since they don't look as short at a glance, I'll leave it here anyway in case someone really wants a one-liner :-)

Also, replaced 'new Array' with 'Array' in all solutions to shave off a few more bytes.

151
votes

The most compact solution, because slice is shorter than substring. Subtracting from the end of the string allows to avoid floating point symbol generated by the random function:

Math.random().toString(36).slice(-5);

or even

(+new Date).toString(36).slice(-5);

Update: Added one more approach using btoa method:

btoa(Math.random()).slice(0, 5);
btoa(+new Date).slice(-7, -2);
btoa(+new Date).substr(-7, 5);

// Using Math.random and Base 36:
console.log(Math.random().toString(36).slice(-5));

// Using new Date and Base 36:
console.log((+new Date).toString(36).slice(-5));

// Using Math.random and Base 64 (btoa):
console.log(btoa(Math.random()).slice(0, 5));

// Using new Date and Base 64 (btoa):
console.log(btoa(+new Date).slice(-7, -2));
console.log(btoa(+new Date).substr(-7, 5));
108
votes

A newer version with es6 spread operator:

[...Array(30)].map(() => Math.random().toString(36)[2]).join('')

  • The 30 is an arbitrary number, you can pick any token length you want
  • The 36 is the maximum radix number you can pass to numeric.toString(), which means all numbers and a-z lowercase letters
  • The 2 is used to pick the 3rd index from the random string which looks like this: "0.mfbiohx64i", we could take any index after 0.
106
votes

Something like this should work

function randomString(len, charSet) {
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var randomString = '';
    for (var i = 0; i < len; i++) {
        var randomPoz = Math.floor(Math.random() * charSet.length);
        randomString += charSet.substring(randomPoz,randomPoz+1);
    }
    return randomString;
}

Call with default charset [a-zA-Z0-9] or send in your own:

var randomValue = randomString(5);

var randomValue = randomString(5, 'PICKCHARSFROMTHISSET');
75
votes

function randomstring(L) {
  var s = '';
  var randomchar = function() {
    var n = Math.floor(Math.random() * 62);
    if (n < 10) return n; //1-10
    if (n < 36) return String.fromCharCode(n + 55); //A-Z
    return String.fromCharCode(n + 61); //a-z
  }
  while (s.length < L) s += randomchar();
  return s;
}
console.log(randomstring(5));
68
votes

Random String Generator (Alpha-Numeric | Alpha | Numeric)

/**
 * Pseudo-random string generator
 * http://stackoverflow.com/a/27872144/383904
 * Default: return a random alpha-numeric string
 * 
 * @param {Integer} len Desired length
 * @param {String} an Optional (alphanumeric), "a" (alpha), "n" (numeric)
 * @return {String}
 */
function randomString(len, an) {
  an = an && an.toLowerCase();
  var str = "",
    i = 0,
    min = an == "a" ? 10 : 0,
    max = an == "n" ? 10 : 62;
  for (; i++ < len;) {
    var r = Math.random() * (max - min) + min << 0;
    str += String.fromCharCode(r += r > 9 ? r < 36 ? 55 : 61 : 48);
  }
  return str;
}

console.log(randomString(10));      // i.e: "4Z8iNQag9v"
console.log(randomString(10, "a")); // i.e: "aUkZuHNcWw"
console.log(randomString(10, "n")); // i.e: "9055739230"

While the above uses additional checks for the desired A/N, A, N output, let's break it down the to the essentials (Alpha-Numeric only) for a better understanding:

  • Create a function that accepts an argument (desired length of the random String result)
  • Create an empty string like var str = ""; to concatenate random characters
  • Inside a loop create a rand index number from 0 to 61 (0..9+A..Z+a..z = 62)
  • Create a conditional logic to Adjust/fix rand (since it's 0..61) incrementing it by some number (see examples below) to get back the right CharCode number and the related Character.
  • Inside the loop concatenate to str a String.fromCharCode( incremented rand )

Let's picture the ASCII Character table ranges:

_____0....9______A..........Z______a..........z___________  Character
     | 10 |      |    26    |      |    26    |             Tot = 62 characters
    48....57    65..........90    97..........122           CharCode ranges

Math.floor( Math.random * 62 ) gives a range from 0..61 (what we need).
Let's fix the random to get the correct charCode ranges:

      |   rand   | charCode |  (0..61)rand += fix            = charCode ranges |
------+----------+----------+--------------------------------+-----------------+
0..9  |   0..9   |  48..57  |  rand += 48                    =     48..57      |
A..Z  |  10..35  |  65..90  |  rand += 55 /*  90-35 = 55 */  =     65..90      |
a..z  |  36..61  |  97..122 |  rand += 61 /* 122-61 = 61 */  =     97..122     |

The conditional operation logic from the table above:

   rand += rand>9 ? ( rand<36 ? 55 : 61 ) : 48 ;
// rand +=  true  ? (  true   ? 55 else 61 ) else 48 ;

From the explanation above, here's the resulting alpha-numeric snippet:

function randomString(len) {
  var str = "";                                // String result
  for (var i = 0; i < len; i++) {              // Loop `len` times
    var rand = Math.floor(Math.random() * 62); // random: 0..61
    var charCode = rand += rand > 9 ? (rand < 36 ? 55 : 61) : 48; // Get correct charCode
    str += String.fromCharCode(charCode);      // add Character to str
  }
  return str; // After all loops are done, return the concatenated string
}

console.log(randomString(10)); // i.e: "7GL9F0ne6t"

Or if you will:

const randomString = (n, r='') => {
  while (n--) r += String.fromCharCode((r=Math.random()*62|0, r+=r>9?(r<36?55:61):48));
  return r;
};

console.log(randomString(10))
40
votes

The simplest way is:

(new Date%9e6).toString(36)

This generate random strings of 5 characters based on the current time. Example output is 4mtxj or 4mv90 or 4mwp1

The problem with this is that if you call it two times on the same second, it will generate the same string.

The safer way is:

(0|Math.random()*9e6).toString(36)

This will generate a random string of 4 or 5 characters, always diferent. Example output is like 30jzm or 1r591 or 4su1a

In both ways the first part generate a random number. The .toString(36) part cast the number to a base36 (alphadecimal) representation of it.

28
votes

To meet requirement [a-zA-Z0-9] and length=5 use

btoa(Math.random()).substr(10, 5);

Lowercase letters, uppercase letters, and numbers will occur.

24
votes

I know everyone has got it right already, but i felt like having a go at this one in the most lightweight way possible(light on code, not CPU):

function rand(length, current) {
  current = current ? current : '';
  return length ? rand(--length, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".charAt(Math.floor(Math.random() * 60)) + current) : current;
}

console.log(rand(5));

It takes a bit of time to wrap your head around, but I think it really shows how awesome javascript's syntax is.

23
votes

Here are some easy one liners. Change new Array(5) to set the length.

Including 0-9a-z

new Array(5).join().replace(/(.|$)/g, function(){return ((Math.random()*36)|0).toString(36);})

Including 0-9a-zA-Z

new Array(5).join().replace(/(.|$)/g, function(){return ((Math.random()*36)|0).toString(36)[Math.random()<.5?"toString":"toUpperCase"]();});
17
votes

In case anyone is interested in a one-liner (although not formatted as such for your convenience) that allocates the memory at once (but note that for small strings it really does not matter) here is how to do it:

Array.apply(0, Array(5)).map(function() {
    return (function(charset){
        return charset.charAt(Math.floor(Math.random() * charset.length))
    }('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'));
}).join('')

You can replace 5 by the length of the string you want. Thanks to @AriyaHidayat in this post for the solution to the map function not working on the sparse array created by Array(5).

17
votes

If you are using Lodash or Underscore, then it so simple:

var randomVal = _.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 5).join('');
17
votes

Generate a secure random alphanumeric Base-62 string:

function generateUID(length)
{
    return window.btoa(Array.from(window.crypto.getRandomValues(new Uint8Array(length * 2))).map((b) => String.fromCharCode(b)).join("")).replace(/[+/]/g, "").substring(0, length);
}

console.log(generateUID(22)); // "yFg3Upv2cE9cKOXd7hHwWp"
console.log(generateUID(5)); // "YQGzP"
14
votes

Here's the method I created.
It will create a string containing both uppercase and lowercase characters.
In addition I've included the function that will created an alphanumeric string too.

Working examples:
http://jsfiddle.net/greatbigmassive/vhsxs/ (alpha only)
http://jsfiddle.net/greatbigmassive/PJwg8/ (alphanumeric)

function randString(x){
    var s = "";
    while(s.length<x&&x>0){
        var r = Math.random();
        s+= String.fromCharCode(Math.floor(r*26) + (r>0.5?97:65));
    }
    return s;
}

Upgrade July 2015
This does the same thing but makes more sense and includes all letters.

var s = "";
while(s.length<x&&x>0){
    v = Math.random()<0.5?32:0;
    s += String.fromCharCode(Math.round(Math.random()*((122-v)-(97-v))+(97-v)));
}
14
votes
const c = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
const s = [...Array(5)].map(_ => c[~~(Math.random()*c.length)]).join('')
14
votes

Improved @Andrew's answer above :

Array.from({ length : 1 }, () => Math.random().toString(36)[2]).join('');

Base 36 conversion of the random number is inconsistent, so selecting a single indice fixes that. You can change the length for a string with the exact length desired.

13
votes

Assuming you use underscorejs it's possible to elegantly generate random string in just two lines:

var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var random = _.sample(possible, 5).join('');
13
votes

One liner:

Array(15).fill(null).map(() => Math.random().toString(36).substr(2)).join('')
// Outputs: 0h61cbpw96y83qtnunwme5lxk1i70a6o5r5lckfcyh1dl9fffydcfxddd69ada9tu9jvqdx864xj1ul3wtfztmh2oz2vs3mv6ej0fe58ho1cftkjcuyl2lfkmxlwua83ibotxqc4guyuvrvtf60naob26t6swzpil
10
votes

Fast and improved algorithm. Does not guarantee uniform (see comments).

function getRandomId(length) {
    if (!length) {
        return '';
    }

    const possible =
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let array;

    if ('Uint8Array' in self && 'crypto' in self && length <= 65536) {
        array = new Uint8Array(length);
        self.crypto.getRandomValues(array);
    } else {
        array = new Array(length);

        for (let i = 0; i < length; i++) {
            array[i] = Math.floor(Math.random() * 62);
        }
    }

    let result = '';

    for (let i = 0; i < length; i++) {
        result += possible.charAt(array[i] % 62);
    }

    return result;
}
9
votes

How about this compact little trick?

var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var stringLength = 5;

function pickRandom() {
    return possible[Math.floor(Math.random() * possible.length)];
}

var randomString = Array.apply(null, Array(stringLength)).map(pickRandom).join('');

You need the Array.apply there to trick the empty array into being an array of undefineds.

If you're coding for ES2015, then building the array is a little simpler:

var randomString = Array.from({ length: stringLength }, pickRandom).join('');
9
votes

You can loop through an array of items and recursively add them to a string variable, for instance if you wanted a random DNA sequence:

function randomDNA(len) {
  len = len || 100
  var nuc = new Array("A", "T", "C", "G")
  var i = 0
  var n = 0
  s = ''
  while (i <= len - 1) {
    n = Math.floor(Math.random() * 4)
    s += nuc[n]
    i++
  }
  return s
}

console.log(randomDNA(5));
8
votes
function randomString (strLength, charSet) {
    var result = [];

    strLength = strLength || 5;
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    while (--strLength) {
        result.push(charSet.charAt(Math.floor(Math.random() * charSet.length)));
    }

    return result.join('');
}

This is as clean as it will get. It is fast too, http://jsperf.com/ay-random-string.

8
votes

The problem with responses to "I need random strings" questions (in whatever language) is practically every solution uses a flawed primary specification of string length. The questions themselves rarely reveal why the random strings are needed, but I would challenge you rarely need random strings of length, say 8. What you invariably need is some number of unique strings, for example, to use as identifiers for some purpose.

There are two leading ways to get strictly unique strings: deterministically (which is not random) and store/compare (which is onerous). What do we do? We give up the ghost. We go with probabilistic uniqueness instead. That is, we accept that there is some (however small) risk that our strings won't be unique. This is where understanding collision probability and entropy are helpful.

So I'll rephrase the invariable need as needing some number of strings with a small risk of repeat. As a concrete example, let's say you want to generate a potential of 5 million IDs. You don't want to store and compare each new string, and you want them to be random, so you accept some risk of repeat. As example, let's say a risk of less than 1 in a trillion chance of repeat. So what length of string do you need? Well, that question is underspecified as it depends on the characters used. But more importantly, it's misguided. What you need is a specification of the entropy of the strings, not their length. Entropy can be directly related to the probability of a repeat in some number of strings. String length can't.

And this is where a library like EntropyString can help. To generate random IDs that have less than 1 in a trillion chance of repeat in 5 million strings using entropy-string:

import {Random, Entropy} from 'entropy-string'

const random = new Random()
const bits = Entropy.bits(5e6, 1e12)

const string = random.string(bits)

"44hTNghjNHGGRHqH9"

entropy-string uses a character set with 32 characters by default. There are other predefined characters sets, and you can specify your own characters as well. For example, generating IDs with the same entropy as above but using hex characters:

import {Random, Entropy, charSet16} from './entropy-string'

const random = new Random(charSet16)
const bits = Entropy.bits(5e6, 1e12)

const string = random.string(bits)

"27b33372ade513715481f"

Note the difference in string length due to the difference in total number of characters in the character set used. The risk of repeat in the specified number of potential strings is the same. The string lengths are not. And best of all, the risk of repeat and the potential number of strings is explicit. No more guessing with string length.

7
votes

Case Insensitive Alphanumeric Chars:

function randStr(len) {
  let s = '';
  while (s.length < len) s += Math.random().toString(36).substr(2, len - s.length);
  return s;
}

// usage
console.log(randStr(50));

The benefit of this function is that you can get different length random string and it ensures the length of the string.

Case Sensitive All Chars:

function randStr(len) {
  let s = '';
  while (len--) s += String.fromCodePoint(Math.floor(Math.random() * (126 - 33) + 33));
  return s;
}

// usage
console.log(randStr(50));

Custom Chars

function randStr(len, chars='abc123') {
  let s = '';
  while (len--) s += chars[Math.floor(Math.random() * chars.length)];
  return s;
}

// usage
console.log(randStr(50));
console.log(randStr(50, 'abc'));
console.log(randStr(50, 'aab')); // more a than b
6
votes

I did not find a clean solution for supporting both lowercase and uppercase characters.

Lowercase only support:

Math.random().toString(36).substr(2, 5)

Building on that solution to support lowercase and uppercase:

Math.random().toString(36).substr(2, 5).split('').map(c => Math.random() < 0.5 ? c.toUpperCase() : c).join('');

Change the 5 in substr(2, 5) to adjust to the length you need.

6
votes

One liner [a-z]:

String.fromCharCode(97 + Math.floor(Math.random() * 26))