我想要一个5个字符的字符串,由从集合[a-zA-Z0-9]中随机选取的字符组成。
用JavaScript实现这一点的最佳方法是什么?
我想要一个5个字符的字符串,由从集合[a-zA-Z0-9]中随机选取的字符组成。
用JavaScript实现这一点的最佳方法是什么?
当前回答
一行使用地图,可以完全控制长度和字符。
const rnd = (len, chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') => [...Array(len)].map(() => chars.charAt(Math.floor(Math.random() * chars.length))).join('')
console.log(rnd(12))
其他回答
这是对doubletap优秀答案的改进。原文有两个缺点,在这里予以解决:
首先,正如其他人所提到的,它很有可能产生短字符串或甚至空字符串(如果随机数为0),这可能会破坏您的应用程序。这里有一个解决方案:
(Math.random().toString(36)+'00000000000000000').slice(2, N+2)
其次,原始和上述解决方案都将字符串大小N限制为16个字符。下面将为任何N返回大小为N的字符串(但请注意,使用N>16不会增加随机性或降低冲突概率):
Array(N+1).join((Math.random().toString(36)+'00000000000000000').slice(2, 18)).slice(0, N)
说明:
选取[0,1)范围内的随机数,即介于0(含)和1(不含)之间。将数字转换为以36为基数的字符串,即使用字符0-9和a-z。用零填充(解决第一个问题)。去掉前导“0.”前缀和额外的填充零。重复字符串足够多次,使其中至少有N个字符(通过将空字符串与用作分隔符的较短随机字符串连接)。从字符串中精确切割N个字符。
进一步思考:
此解决方案不使用大写字母,但在几乎所有情况下(并非双关语)都无关紧要。原始答案中N=16时的最大字符串长度是用Chrome测量的。在Firefox中,N=11。但正如所解释的,第二种解决方案是关于支持任何请求的字符串长度,而不是添加随机性,因此没有太大的区别。至少在Math.random()返回的结果均匀分布的情况下,所有返回的字符串返回的概率相等(无论如何,这不是加密强度随机性)。并非所有可能的大小为N的字符串都可以返回。在第二种解决方案中,这是显而易见的(因为较小的字符串只是被复制),但在原始答案中,这也是正确的,因为在转换为base-36时,最后几位可能不是原始随机位的一部分。具体来说,如果您查看Math.random().toString(36)的结果,您会注意到最后一个字符不是均匀分布的。同样,在几乎所有的情况下,这都无关紧要,但我们从随机字符串的开头而不是结尾对最终字符串进行切片,这样短字符串(例如N=1)就不会受到影响。
更新:
下面是我想出的另外两个功能性风格的单行程序。它们与上述解决方案的不同之处在于:
他们使用一个明确的任意字母表(更通用,适用于要求大写和小写字母的原始问题)。长度为N的所有字符串返回的概率相等(即字符串不包含重复)。它们基于map函数,而不是toString(36)技巧,这使得它们更加简单易懂。
所以,说你选择的字母表是
var s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
那么这两个是等价的,因此您可以选择对您更直观的:
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('');
编辑:
我似乎认为qubyte和Martijn de Milliano提出了类似于后者的解决方案(很好!),但我不知怎么错过了。因为它们一眼看上去不那么短,所以我还是把它放在这里,以防有人真的想要一行:-)
此外,在所有解决方案中,将“new Array”替换为“Array”,以节省更多字节。
如果您使用的是Lodash或Undercore,那么非常简单:
var randomVal = _.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 5).join('');
同样基于doubletap的答案,该方法处理任意长度的随机所需字符(仅限小写),并不断生成随机数,直到收集到足够的字符。
function randomChars(len) {
var chars = '';
while (chars.length < len) {
chars += Math.random().toString(36).substring(2);
}
// Remove unnecessary additional characters.
return chars.substring(0, len);
}
最重要的是,所有的答案都是完美的。但我要补充的是,生成任何随机字符串值都非常好而且快速
函数randomStringGenerator(stringLength){var randomString=“”;//选择变量的空值const allCharacters=“`~!@#$%^&*()_+-={}[]:;\'<>?,./|\\ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijlmnopqrstuvwxyz0123456789'”;//所有字母数字字母列表while(stringLength--){randomString+=allCharacters.substr(Math.floor((Math.random()*allCharacters.length)+1),1);//使用Math.random()从所有字符变量中选择任意值}return randomString;//返回生成的字母数字字符串}console.log(randomStringGenerator(10))//通过输入所需的随机字符串来调用函数
or
console.log(Date.now())//它每次都会产生随机的十三个数字字符值。console.log(Date.now().toString().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>
我已经在这里给出了答案,所以我不会在这里提出另一个解决方案