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

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


当前回答

仅仅一个简单的map或reduce实现就足够了:

const charset: string =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

const random1: string = [...Array(5)]
  .map((_) => charset[Math.floor(Math.random() * charset.length)])
  .join("");

const random2: string = [...Array(5)]
  .reduce<string>(
    (acc) => acc += charset[Math.floor(Math.random() * charset.length)],
    "",
  );

其他回答

回顾

许多答案基于技巧Math.random().toString(36),但这种方法的问题是Math.randum并不总是产生以36为基数至少有5个字符的数字。

让testRnd=n=>console.log(`num dec:${n},num base36:${n.toString(36)},string:${n.toString(36,substr(2,5)}`);[Math.random(),//并且远小于0.5。。。0.5,0.50077160493827161,0.5015432098765432,0.5023148148148148,0.5030864197530864,//还有更多。。。。0.9799597050754459].map(n=>测试Rnd(n));console.log('…等等');以下每个示例(第一个除外)的数字结果少于5个字符(不符合OP问题要求)

这里是“生成器”,允许手动查找这些数字

函数base36Todec(十六进制){hex=十六进制拆分(/\./);return(parseInt(hex[1],36))*(36**-hex[1].length)++(parseInt(hex[0],36);}函数calc(十六进制){设dec=base36Todec(十六进制);msg.innerHTML=`dec:<b>${dec}</b><br>十六进制测试:<b>${dec.toString(36)}</b>`} 函数calc2(dec){msg2.innerHTML=`dec:<b>${dec}</b><br>十六进制测试:<b>${(+dec).toString(36)}</b>`} 让init=“0.za1”;inp.value=init;calc(初始化);键入0-1范围内的数字,使用基数36(0-9,a-z),点后少于5位<br><input-oninput=“calc(this.value)”id=“inp”/><div id=“msg”></div><br>如果上面的<i>十六进制测试</i>在点后给出的数字多于5,那么您可以尝试将dec数字复制到下面的字段,并将一些数字连接到dec数字右侧和/或更改最后一个数字-它有时也会产生数字较少的十六进制<br><input-oninput=“calc2(this.value)”/><br><div id=“msg2”></div>

我已经在这里给出了答案,所以我不会在这里提出另一个解决方案

我已经制作了一个字符串原型,它可以生成一个给定长度的随机字符串。

如果你想要特殊字符,你也可以解密,你可以避免一些。

/**
 * STRING PROTOTYPE RANDOM GENERATOR
 * Used to generate a random string
 * @param {Boolean} specialChars
 * @param {Number} length
 * @param {String} avoidChars
 */
String.prototype.randomGenerator = function (specialChars = false, length = 1, avoidChars = '') {
    let _pattern = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    _pattern += specialChars === true ? '(){}[]+-*/=' : '';
    if (avoidChars && avoidChars.length) {
        for (let char of avoidChars) {
            _pattern = _pattern.replace(char, '');
        }
    }
    let _random = '';
    for (let element of new Array(parseInt(length))) {
        _random += _pattern.charAt(Math.floor(Math.random() * _pattern.length));
    }
    return _random;
};

您可以这样使用:

// Generate password with specialChars which contains 10 chars and avoid iIlL chars
var password = String().randomGenerator(true, 10, 'iIlL');

希望有帮助。

我没有找到支持小写和大写字符的干净解决方案。

仅小写支持:

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

基于该解决方案,支持小写和大写:

Math.random().toString(36).substr(2,5).split(“”).map(c=>Math.randm()<0.5?c.toUpperCase():c).jjoin(“”);

更改substr(2,5)中的5以调整到所需的长度。

您可以使用Web Crypto的API:

console.log(self.crypto.getRandomValues(新Uint32Array(1))[0])

(此处为原始答案)

这是第一个答案的测试脚本(谢谢@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');