在JavaScript中生成随机字符串/字符。

2782
我希望得到一个由随机选取的字符组成的5个字符的字符串,可用字符集为[a-zA-Z0-9]
使用JavaScript,最佳方法是什么?

87
警告:所有答案都不具有“真正的随机”结果!它们只是“伪随机”。在使用随机字符串进行保护或安全时,不要使用它们中的任何一个!!!请尝试使用以下其中一种API:http://www.random.org/ - Ron van der Heijden
22
请注意:HTML5 webcrypto randomness API 提供真正的随机性。 - mikemaccana
6
如果有人在这里寻求生成一个ID或唯一标识符,让你的数据库来完成这项工作,或者使用UUID库。 - Dan
使用JavaScript、Java、Python、Rust和Bash生成随机字符串:https://fe-tool.com/zh-cn/random-password - cwtuan
试试npm库random-ext - undefined
94个回答

15

这是我创建的方法。
它会创建一个包含大小写字母的字符串。
此外,我还包括了一个函数来创建包含字母和数字的字符串。

工作示例:
http://jsfiddle.net/greatbigmassive/vhsxs/(仅字母)
http://jsfiddle.net/greatbigmassive/PJwg8/(字母和数字)

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

2015年7月升级版
该版本与原先功能相同,但更易理解并包含所有字母。

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

使用此函数,您永远不会得到大于“M”的大写字母或小于“n”的小写字母。 - erkanyildiz
真的吗?哦!那我可能会更多地测试它。嗯,然而,考虑到它是一个随机字符串,我们并不真正关心它包含什么字母(只要它们是随机的),那么它仍然能够实现我们想要的功能,这才是最重要的,但是是的,我们会提供升级,谢谢。 - Adam

15

改进了@Andrew上面的答案:

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

将随机数转换为36进制会导致不一致性,因此选择一个单独的索引来解决这个问题。您可以更改所需长度的字符串的长度。


14
假设您使用 underscorejs,只需两行代码即可优雅地生成随机字符串:
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var random = _.sample(possible, 5).join('');

6
这将使返回值具有所有唯一的字符。此外,字符串的长度限制为变量 possible 的长度。 - Yefu

13
function randomString (strLength, charSet) {
    var result = [];
    
    strLength = strLength || 5;
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    
    while (strLength--) { // (note, fixed typo)
        result.push(charSet.charAt(Math.floor(Math.random() * charSet.length)));
    }
    
    return result.join('');
}

这是最干净的状态了。它速度也很快,http://jsperf.com/ay-random-string


对我来说,这总是会生成长度为 strLength - 1 的随机字符串 :-/ - AlexGrafe
4
--strLength改为strLength--对我来说解决了问题。 - AlexGrafe
@Gajus 我拿了自由来修复明显的错别字。应该是 strLength-- 后缀,而不是前缀。 - Fattie
谢谢您先生。将其包装在函数中使得复制/粘贴变得更加容易 ❤️ - Sagive

11

快速且改进的算法。不能保证均匀性(请参见注释)。

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

4
回答很棒,但概率并不均匀。共有62个可能的字符,而crypto.getRandomValues返回256个唯一值之一。因为256不能被62整除,所以得到A-H字符的概率稍微高一些。我认为最好的解决方案是像YouTube那样,只需将2个额外的字符(可能是“-”和“_”)添加到字符集中。总之,非常出色 - 这个答案需要更多的支持 :) - TeWu
添加“-”和“_”是个好主意,因为这样可以得到完整的URL安全的base64集合。 - cowbert

11

虽然这个答案与其他答案几乎相似,但它的不同之处在于它使用了:

  • repeat 创建 5 个字符(可以概括为 n
  • /./g 的正则表达式替换这五个字符
  • 公式是从一个 62 个字符 A-Za-z0-9 字符串中随机选择一个字符

let ans = "x".repeat(5)
             .replace(/./g, c => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[Math.floor(Math.random() * 62) ] );
console.log(ans);


10

不区分大小写的字母数字字符:

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

这个函数的好处是可以获取不同长度的随机字符串,并且确保字符串的长度。

区分大小写的所有字符:

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

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

定制字符

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


这个答案更适合我的用例。如果您能像接受的答案中那样添加一个 var possible,那么函数的结果将更具可配置性,这将很酷。 - Denis.Sabolotni

10

您可以循环遍历一个项目数组,并将它们递归地添加到字符串变量中,例如,如果您想要一个随机的DNA序列:

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


10

这个小巧的技巧怎么样?

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('');
你需要在那里使用 Array.apply 来欺骗空数组成为一组未定义的数组。
如果你正在编写 ES2015,那么构建数组就更简单了。
var randomString = Array.from({ length: stringLength }, pickRandom).join('');

9
针对“我需要随机字符串”的问题(无论使用何种语言),实际上几乎每个解决方案都存在缺陷,主要是在字符串长度的规范上。这些问题本身很少透露需要随机字符串的原因,但我想质疑你是否真的需要长度为8的随机字符串。你需要的通常是一些唯一字符串,例如用作某些目的的标识符。
有两种方法可以获得严格唯一的字符串:确定性方式(不是随机的)和存储/比较方式(费力)。我们该怎么办呢?我们放弃了。我们选择采用概率唯一性。也就是说,我们接受存在一些(不管多小)风险,即我们的字符串可能不唯一。这就是理解碰撞概率有所帮助的地方。
因此,我将不变的需求重新表述为需要一些具有小概率重复的字符串数量。举个具体的例子,假设您想生成500万个ID。您不希望存储和比较每个新字符串,并且希望它们是随机的,因此您接受一定的重复风险。例如,假设重复的概率小于1兆分之一。那么,您需要多长的字符串?这个问题没有明确说明,因为它取决于所使用的字符。但更重要的是,这是错误的。你需要的是字符串的熵的规范,而不是它们的长度。熵可以直接与某些字符串中重复出现的概率相关联。字符串长度则无法做到。
这就是像EntropyString这样的库可以帮助的地方。使用entropy-string生成随机ID,在500万个字符串中具有小于1兆分之一的重复几率:
import {Random, Entropy} from 'entropy-string'

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

const string = random.string(bits)

"44hTNghjNHGGRHqH9"

entropy-string 默认使用包含32个字符的字符集。还有其他预定义的字符集,您也可以指定自己的字符集。例如,使用十六进制字符生成与上述相同熵值的 ID:

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

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

const string = random.string(bits)

"27b33372ade513715481f"

请注意,由于使用的字符集中字符总数的差异,字符串长度存在差异。指定数量的潜在字符串中重复的风险相同,但字符串长度不同。最好的是,重复的风险和潜在字符串数量是明确的,不需要猜测字符串长度。


谢谢!你的评论让我意识到我不应该随机生成ID。看起来nanoidentropy-string更受欢迎,而且对于我的目的来说似乎同样好。 - Altay_H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接