Generate random string/characters in JavaScript

2018-12-31 02:19发布

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条回答
有味是清欢
2楼-- · 2018-12-31 03:13

Teach a man to fish:

Programmers cut paper with lasers, not chainsaws. Using fringe, language specific methods to produce the smallest, most obfuscated code is cute and all, but will never offer a complete solution. You have to use the right tool for the job.

What you want is a string of characters, and characters are represented by bytes. And, we can represent a byte in JavaScript using a number. So then, we should generate a list of these numbers, and cast them as strings. You don't need Date, or base64; Math.random() will get you a number, and String.fromCharCode() will turn it into a string. Easy.

But, which number equals which character? UTF-8 is the primary standard used on the web to interpret bytes as characters (although JavaScript uses UTF-16 internally, they overlap). The programmer's way of solving this problem is to look into the documentation.

UTF-8 lists all the keys on the keyboard in the numbers between 0 and 128. Some are non-printing. Simply pick out the characters you want in your random strings, and search for them, using randomly generated numbers.

Bellow is a function that takes a virtually infinite length, generates a random number in a loop, and searches for all the printing characters in the lower 128 UTF-8 codes. Entropy is inherent, since not all random numbers will hit every time (non-printing characters, white space, etc). It will also perform faster as you add more characters.

I've included most of the optimizations discussed in the thread:

  • The double tilde is faster than Math.floor
  • "if" statements are faster than regular expressions
  • pushing to an array is faster than string concatenation

function randomID(len) {
  var char;
  var arr = [];
  var len = len || 5;

  do {
    char = ~~(Math.random() * 128);

    if ((
        (char > 47 && char < 58) || // 0-9
        (char > 64 && char < 91) || // A-Z
        (char > 96 && char < 123) // a-z

        // || (char > 32 && char < 48) // !"#$%&,()*+'-./
        // || (char > 59 && char < 65) // <=>?@
        // || (char > 90 && char < 97) // [\]^_`
        // || (char > 123 && char < 127) // {|}~
      )
      //security conscious removals: " ' \ ` 
      //&& (char != 34 && char != 39 && char != 92 && char != 96) 

    ) { arr.push(String.fromCharCode(char)) }

  } while (arr.length < len);

  return arr.join('')
}

var input = document.getElementById('length');

input.onfocus = function() { input.value = ''; }

document.getElementById('button').onclick = function() {
  var view = document.getElementById('string');
  var is_number = str => ! Number.isNaN( parseInt(str));
    
  if ( is_number(input.value))
    view.innerText = randomID(input.value);
  else
    view.innerText = 'Enter a number';
}
#length {
  width: 3em;
  color: #484848;
}

#string {
  color: #E83838;
  font-family: 'sans-serif';
  word-wrap: break-word;
}
<input id="length" type="text" value='#'/>
<input id="button" type="button" value="Generate" />
<p id="string"></p>

Why do it in this tedious way? Because you can. You're a programmer. You can make a computer do anything! Besides, what if you want a string of Hebrew characters? It's not hard. Find those characters in the UTF-8 standard and search for them. Free yourself from these McDonald methods like toString(36).

Sometimes, dropping down to a lower level of abstraction is what's needed to create a real solution. Understanding the fundamental principals at hand can allow you to customize your code how you'd like. Maybe you want an infinitely generated string to fill a circular buffer? Maybe you want all of your generated strings to be palindromes? Why hold yourself back?

查看更多
十年一品温如言
3楼-- · 2018-12-31 03:14

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.

查看更多
有味是清欢
4楼-- · 2018-12-31 03:17

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);
查看更多
临风纵饮
5楼-- · 2018-12-31 03:17

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

查看更多
路过你的时光
6楼-- · 2018-12-31 03:18

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('');
查看更多
路过你的时光
7楼-- · 2018-12-31 03:18

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.

查看更多
登录 后发表回答