我想要一个5个字符的字符串,由从集合[a-zA-Z0-9]中随机选取的字符组成。

用JavaScript实现这一点的最佳方法是什么?


当前回答

短、简单、可靠

返回5个随机字符,而不是此处找到的一些排名最高的答案。

Math.random().toString(36).slice(2, 7);

其他回答

如果您无法键入字符集,使用String.fromCharCode和范围内的Math.random可以在任何Unicode代码点范围内创建随机字符串。例如,如果您想要17个随机藏文字符,可以输入ranstr(17,0xf00,0xfff),其中(0xf00,0xff)对应于藏文Unicode块。在我的实现中,如果不指定代码点范围,生成器将输出ASCII文本。函数ranchar(a,b){a=(a==未定义?0:a);b=(b===未定义?127:b);return String.fromCharCode(Math.floor(Math.random()*(b-a)+a));}函数transtr(len,a,b){a=a||32;var结果=“”;对于(var i=0;i<len;i++){结果+=ranchar(a,b)}返回结果;}//以下是随机Unicode块的一些示例console.log('拉丁语基本块:'+transtr(10,0x000,0x007f))console.log('拉丁语-1增补块:'+transtr(10,0x080,0x0ff))console.log('货币符号块中:'+transtr(10,0x20a0,0x20cf))console.log('在类字母符号块中:'+transtr(10,0x2100,0x214f))console.log('在Dingbats块中:'+transtr(10,0x2700,0x27bf))

这是第一个答案的测试脚本(谢谢@csharptest.net)

该脚本运行makeid()100万次,如您所见,5不是一个非常独特的脚本。以10的字符长度运行它是非常可靠的。我已经运行了大约50次,还没有看到重复的:-)

注意:节点堆栈大小限制超过了大约400万,因此您无法运行这500万次,它永远无法完成。

function makeid()
{
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for( var i=0; i < 5; i++ )
        text += possible.charAt(Math.floor(Math.random() * possible.length));

    return text;
}

ids ={}
count = 0
for (var i = 0; i < 1000000; i++) {
    tempId = makeid();
    if (typeof ids[tempId] !== 'undefined') {
        ids[tempId]++;
        if (ids[tempId] === 2) {
            count ++;
        }
        count++;
    }else{
        ids[tempId] = 1;
    }
}
console.log("there are "+count+ ' duplicate ids');

最简单的方法是:

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

这将基于当前时间生成5个字符的随机字符串。示例输出为4mtxj或4mv90或4mwp1

这样做的问题是,如果您在同一秒内调用它两次,它将生成相同的字符串。

更安全的方法是:

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

这将生成一个4或5个字符的随机字符串,总是不同的。示例输出类似于30jzm或1r591或4su1a

在这两种方式中,第一部分生成一个随机数。.toString(36)部分将数字转换为它的base36(字母十进制)表示形式。

Math.random不适合这种情况

服务器端

使用节点加密模块-

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

// "bb5dc8842ca31d4603d6aa11448d1654"

生成的字符串将是您生成的随机字节的两倍长;编码为十六进制的每个字节是2个字符。20字节将是40个十六进制字符。


客户端

使用浏览器的加密模块crypto.getRandomValues-

通过crypto.getRandomValues()方法,可以获得加密的强随机值。作为参数给出的数组用随机数填充(在其密码意义上是随机的)。

//dec2hex::整数->字符串//即0-255->“00”-“f”功能dec2hex(dec){return dec.toString(16).padStart(2,“0”)}//generateId::整数->字符串函数生成器ID(len){var arr=新Uint8Array((len||40)/2)window.crypto.getRandomValues(arr)return Array.from(arr,dec2hex).join(“”)}console.log(generateId())//“82defcf324571e70b0521d79cce2bf3ffccd69”console.log(generateId(20))//“c1a050a4cd1556948d41”

分步控制台示例-

> 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 ]

对于IE11支持,您可以使用-

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

有关浏览器覆盖范围,请参阅https://caniuse.com/#feat=getrandomvalues


客户端(旧浏览器)

如果您必须支持旧浏览器,请考虑像uuid这样的东西-

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

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

//可以将7更改为2以获得更长的结果。让r=(Math.random()+1).toString(36).substring(7);console.log(“随机”,r);

注:上述算法有以下缺点:

它将生成0到6个字符之间的任何字符,这是因为字符串化浮点时会删除尾随零。这在很大程度上取决于用于字符串化浮点数的算法,这非常复杂。(请参阅论文“如何准确打印浮点数字”。)根据实现的不同,Math.random()可能会产生可预测的(“看起来随机”但不是真正随机的)输出。当需要保证唯一性或不可预测性时,生成的字符串不适合。即使它产生了6个统一的随机、不可预测的字符,由于生日悖论,在只产生了大约50000个字符串之后,你也可以看到重复的字符。(平方英尺(36^6)=4656)