我想要一个5个字符的字符串,由从集合[a-zA-Z0-9]中随机选取的字符组成。
用JavaScript实现这一点的最佳方法是什么?
我想要一个5个字符的字符串,由从集合[a-zA-Z0-9]中随机选取的字符组成。
用JavaScript实现这一点的最佳方法是什么?
当前回答
这是对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”,以节省更多字节。
其他回答
教人钓鱼:
程序员用激光切割纸张,而不是电锯。使用边缘的、特定于语言的方法来生成最小、最模糊的代码是非常可爱的,但永远不会提供完整的解决方案。你必须使用合适的工具来完成这项工作。
您需要的是字符串,字符由字节表示。而且,我们可以用数字在JavaScript中表示一个字节。因此,我们应该生成这些数字的列表,并将它们转换为字符串。你不需要Date或base64;Math.random()将获得一个数字,String.fromCharCode()将其转换为字符串。容易的
但是,哪个数字等于哪个字符?UTF-8是web上用于将字节解释为字符的主要标准(尽管JavaScript内部使用UTF-16,但它们是重叠的)。程序员解决这个问题的方法是查看文档。
UTF-8以0到128之间的数字列出键盘上的所有键。有些是非打印的。只需在随机字符串中选择所需的字符,然后使用随机生成的数字搜索它们。
Bellow是一个几乎无限长的函数,在循环中生成一个随机数,并搜索低128位UTF-8代码中的所有打印字符。熵是固有的,因为并非所有随机数每次都会命中(非打印字符、空格等)。当您添加更多字符时,它的执行速度也会更快。
我已经包含了线程中讨论的大多数优化:
双颚化符比Math.floor快“if”语句比正则表达式更快推送到数组比字符串串联更快
函数randomID(len){var字符;var arr=[];var len=长度||5;做{char=~~(Math.random()*128);如果(((字符>47和字符<58)| |//0-9(字符>64和字符<91)||//A-Z(字符>96和字符<123)//a-z//||(字符>32&&字符<48)//!"#$%&,()*+'-.///|(字符>59&&字符<65)//<=>@//|(字符>90&&字符<97)//[\]^_`//|(字符>123&&字符<127)//{|}~)//安全意识删除:“'\`//&&(char!=34&&char!=39&&char!=92&&char!=96)){arr.push(String.fromCharCode(char))}}而(arr.length<len);return arr.join(“”)}var input=document.getElementById('length');input.onfocus=函数(){input.value=“”;}document.getElementById('button').onclick=函数(){var view=document.getElementById(“字符串”);var is_number=str=>!编号.isNaN(parseInt(str));if(is_number(input.value))view.innerText=随机ID(input.value);其他的view.innerText='输入数字';}#长度,长度{宽度:3em;颜色:#484848;}#字符串{颜色:#E83838;字体系列:'sans-serif';换行:换行;}<input id=“length”type=“text”value=“#”/><input id=“button”type=“button“value=“Generate”/><p id=“string”></p>
为什么要用这种乏味的方式?因为你可以。你是个程序员。你可以让电脑做任何事情!此外,如果你想要一串希伯来语字符呢?这并不难。在UTF-8标准中查找这些字符并搜索它们。将自己从这些McDonald方法中解放出来,比如toString(36)。
有时,创建真正的解决方案需要降低抽象级别。了解手头的基本原理可以让您按照自己的意愿定制代码。也许你想要一个无限生成的字符串来填充一个循环缓冲区?也许你希望所有生成的字符串都是回文?为什么要克制自己?
以下代码将使用npm包加密随机字符串生成大小为[a-zA-Z0-9]的加密安全随机字符串。使用以下方法安装:
npm install crypto-random-string
要在集合[a-zA-Z0-9]中获得30个字符的随机字符串:
const cryptoRandomString = require('crypto-random-string');
cryptoRandomString({length: 100, type: 'base64'}).replace(/[/+=]/g,'').substr(-30);
摘要:我们正在替换一个大的随机base64字符串中的/,+,=,并获取最后N个字符。
PS:在子字符串中使用-N
快速和改进的算法。不保证统一(见注释)。
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;
}
为了满足要求[a-zA-Z0-9]和5个字符的长度,使用
对于浏览器:
btoa(Math.random().toString()).substring(10,15);
对于NodeJS:
Buffer.from(Math.random().toString()).toString("base64").substring(10,15);
将出现小写字母、大写字母和数字。
(字体兼容)
随机字符串生成器(字母数字|字母数字|数字)
/***伪随机串发生器* http://stackoverflow.com/a/27872144/383904*默认值:返回随机字母数字字符串* *@param{Integer}len所需长度*@param{String}an可选(字母数字),“a”(字母),“n”(数字)*@return{字符串}*/函数randomString(len,an){an=an&&an.toLowerCase();var str=“”,i=0,min=an==“a”?10 : 0,max=an==“n”?10 : 62;对于(;i++<len;){var r=数学随机()*(最大值-最小值)+最小值<<0;str+=String.fromCharCode(r+=r>9?r<36?55:61:48);}返回str;}console.log(randomString(10));//即:“4Z8INGag9v”console.log(randomString(10,“a”));//即:“aUkZuHNcWw”console.log(randomString(10,“n”));//即:“9055739230”
虽然以上使用了对期望的A/N、A、N输出的附加检查,让我们将其分解为基本要素(仅限字母数字),以便更好地理解:
创建一个接受参数的函数(随机字符串结果的所需长度)创建一个空字符串,如var str=“”;连接随机字符在循环内创建一个从0到61(0..9+a.Z+a..Z=62)的rand索引编号创建一个条件逻辑来调整/修复rand(因为它是0..61),将其递增一些数字(参见下面的示例),以获取正确的CharCode编号和相关字符。在循环内部连接到str一个String.fromCharCode(递增rand)
让我们想象一下ASCII字符表范围:
_____0....9______A..........Z______a..........z___________ Character
| 10 | | 26 | | 26 | Tot = 62 characters
48....57 65..........90 97..........122 CharCode ranges
Math.floor(Math.random*62)给出了从0..61(我们需要的)的范围。让我们修复随机数以获得正确的charCode范围:
| rand | charCode | (0..61)rand += fix = charCode ranges |
------+----------+----------+--------------------------------+-----------------+
0..9 | 0..9 | 48..57 | rand += 48 = 48..57 |
A..Z | 10..35 | 65..90 | rand += 55 /* 90-35 = 55 */ = 65..90 |
a..z | 36..61 | 97..122 | rand += 61 /* 122-61 = 61 */ = 97..122 |
上表中的条件运算逻辑:
rand += rand>9 ? ( rand<36 ? 55 : 61 ) : 48 ;
// rand += true ? ( true ? 55 else 61 ) else 48 ;
根据上面的解释,下面是生成的字母数字代码段:
函数randomString(len){var str=“”;//字符串结果对于(var i=0;i<len;i++){//循环“len”次数var rand=数学地板(Math.random()*62);//随机:0..61var charCode=rand+=rand>9?(兰特<36?55:61):48;//获取正确的charCodestr+=字符串.fromCharCode(charCode);//将字符添加到str}返回str;//完成所有循环后,返回连接字符串}console.log(randomString(10));//即:“7GL9F0ne6t”
或者,如果您愿意:
const randomString=(n,r=“”)=>{而(n--)r+=String.fromCharCode((r=Math.random()*62|0,r+=r>9?(r<36?55:61):48));返回r;};console.log(randomString(10))