问:

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

使用 JavaScript 执行此操作的最佳方法是什么?

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

答1:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

我认为这对你有用:

函数 makeid(length) { var 结果 = ‘’; var characters = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789’; var charactersLength = characters.length; for ( var i = 0; i < length; i++ ) { 结果 += characters.charAt(Math.floor(Math.random() * charactersLength)); } 返回结果; } console.log(makeid(5));

@dan_waterworth 在几乎任何的情况下这可能都无关紧要:codinghorror.com/blog/2009/01/…

它可能看起来不对,但不需要 floor:for(var text=''; text.length < 5;) text += possible.charAt(Math.random() * possible.length)

@dan_waterworth,实际上,出于某种原因,+= 通常更快,甚至在循环内部使用 - jsperf.com/join-vs-concatenation

@JonathanPaulson 给我看数字。请参阅带有 jsperf 链接或 jsperf.com/sad-tragedy-of-microoptimization 或 sitepen.com/blog/2008/05/09/string-performance-an-analysis 等的先前评论。此外,此问题仅涉及 5 个连接。

@codenamejames 请不要在您的密码加盐中使用它。它只是伪随机不安全。假设您使用的是 Node(如果您在客户端加盐,我什至不确定从哪里开始),请改用 crypto。

答2:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

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

注意:上述算法有以下弱点:

由于在对浮点进行字符串化时会删除尾随零,因此它将生成 0 到 6 个字符之间的任何字符。

它在很大程度上取决于用于对浮点数进行字符串化的算法,这非常复杂。 (请参阅论文“如何准确打印浮点数”。)

Math.random() 可能会根据实现产生可预测的(“随机的”但不是真正随机的)输出。当您需要保证唯一性或不可预测性时,生成的字符串不适合。

即使它生成了 6 个均匀随机、不可预测的字符,由于生日悖论,您可能会在仅生成大约 50,000 个字符串后看到重复的字符。 (sqrt(36^6) = 46656)

Math.random().toString(36).substr(2, 5),因为 .substring(7) 导致它超过 5 个字符。满分,还是!

@Scoop JavaScript 中数字类型的 toString 方法采用可选参数将数字转换为给定的基数。例如,如果您传递两个,您将看到以二进制表示的数字。类似于十六进制(以 16 为底),以 36 为底使用字母来表示 9 以外的数字。通过将随机数转换为以 36 为底,您将得到一堆看似随机的字母和数字。

看起来很漂亮,但在少数情况下会生成空字符串!如果 random 返回 0, 0.5, 0.25, 0.125... 将导致空字符串或短字符串。

@gertas 这可以通过(Math.random() + 1).toString(36).substring(7);来避免

@hacklikecrack,重复发生是因为 substring(7) 从 base-36 字符串的最低有效部分获取数字。 toString(36) 似乎将随机数转换为 16 位 base-36 字符串,但所需的精度为 36^16 = 7.958e24 个可能的数字,其中 Math.random() 的精度仅为 4.5e15。用 .slice(2,5) 从最重要的一端取数字可以解决这个问题:5 digit example

答3:

huntsbot.com洞察每一个产品背后的需求与收益,从而捕获灵感

Math.random is bad for this kind of thing

选项1

如果您能够做到这一点 server 端,只需使用 crypto 模块 -

var crypto = require("crypto");

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

// "bb5dc8842ca31d4603d6aa11448d1654"

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

选项 2

如果您必须在客户端执行此操作,也许可以尝试 uuid 模块 -

var uuid = require("uuid");

var id = uuid.v4();

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

选项 3

如果您必须在客户端执行此操作并且您不必支持旧浏览器,则可以在没有依赖关系的情况下执行此操作 -

// dec2hex :: Integer -> String // 即 0-255 -> ‘00’-‘ff’ function dec2hex (dec) { return dec.toString(16).padStart(2, “0”) } // generateId :: Integer -> String function generateId (len) { var arr = new Uint8Array((len || 40) / 2) window.crypto.getRandomValues(arr) return Array.from(arr, dec2hex).join(‘’) } console.log(generateId()) // “82defcf324571e70b0521d79cce2bf3fffccd69” console.log(generateId(20)) // “c1a050a4cd1556948d41”

有关 crypto.getRandomValues 的更多信息 -

crypto.getRandomValues() 方法可让您获得加密的强随机值。作为参数给出的数组填充了随机数(在其密码学意义上是随机的)。

这是一个小控制台示例 -

> 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 可以很好地为事物分配 ID,但出于这个(可能还有其他)原因,将其用作随机字符串并不是一个好主意。

选项 3 中不需要 .map()。Array.from(arr, dec2hex).join('') === Array.from(arr).map(dec2hex).join('')。感谢您向我介绍这些功能 :-)

您应该在答案中提到选项 2 也需要 node.js 才能工作,它不是纯 JavaScript。

虽然在密码学上更安全,但这实际上并不能满足问题的要求,因为它只输出 0-9 和 af(十六进制),而不是 0-9、az、AZ。

@AneesAhmed777 为 dec2hex 提供了一个示例编码器。无论您选择如何表示字节,都由您决定。我用你的建议更新了帖子。

答4:

huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求

简短、简单、可靠

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

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

如果 Math.random().toString(36) 返回一个少于 5 个字符的数字怎么办?

嗯,这是来自@Aperçu 的一个有趣的控诉,我并不是说我发明了这个解决方案,但多年来我一直在我的项目中使用它。这与您提到的评论无关。而且我很确定,在 SO 中,最重要的是在正确的地方提供最有用的信息,即使它已经存在于其他地方也是如此。幸运的是,似乎至少有 51 人发现这个答案很有用,不客气!

@rinogo Math.random() 可以返回 0 但不能返回 1 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

我运行了这段代码 1,000,000,000 次,但仍然没有得到一个空字符串:jsfiddle.net/mtp5730r 我会说你得到一个空字符串是很安全的。

统计上不太可能发生的事件并不意味着它是安全的。如果有人将其用于任何与安全相关的活动,他们就是在赌 Math.random 不返回 0 的可能性。希望您永远不必调试此事件

答5:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

这是对 doubletap’s excellent answer 的改进。原版有两个缺点,这里要解决:

首先,正如其他人所提到的,它产生短字符串甚至是空字符串(如果随机数为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(不包括)之间。将数字转换为 base-36 字符串,即使用字符 0-9 和 az。用零填充(解决第一个问题)。切掉前面的“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('');

Array.apply(null, Array(N)).map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('');

编辑:

我似乎 qubyte 和 Martijn de Milliano 提出了与后者类似的解决方案(赞!),我不知何故错过了。因为它们一目了然,所以我还是把它留在这里,以防有人真的想要单线:-)

此外,在所有解决方案中将 ‘new Array’ 替换为 ‘Array’ 以减少更多字节。

为什么不加1? (Math.random()+1).toString(36).substring(7);

因为加 1 并不能解决这里讨论的两个问题。例如,(1).toString(36).substring(7) 产生一个空字符串。

使用 Math.random().toString(36).substring(2,7) 会产生一个更像 .substring(2, n+2) 的预期结果

Array.apply(null, {length: 5}).map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('')

这很棒,但是当在 N=16 的 Firefox 中执行时,最后约 6 位数字最终为零……(但它确实满足了 OP 对 5 个随机字符的需求。)

答6:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

最紧凑的解决方案,因为 slice 比 substring 短。从字符串的末尾减去可以避免 random 函数生成的浮点符号:

Math.random().toString(36).slice(-5);

甚至

(+new Date).toString(36).slice(-5);

更新: 使用 btoa 方法添加了另一种方法:

btoa(Math.random()).slice(0, 5);

btoa(+new Date).slice(-7, -2);

btoa(+new Date).substr(-7, 5);

// 使用 Math.random 和 Base 36:console.log(Math.random().toString(36).slice(-5)); // 使用新日期和基数 36:console.log((+new Date).toString(36).slice(-5)); // 使用 Math.random 和 Base 64 (btoa): console.log(btoa(Math.random()).slice(0, 5)); // 使用 new Date 和 Base 64 (btoa): console.log(btoa(+new Date).slice(-7, -2)); console.log(btoa(+new Date).substr(-7, 5));

Math.random().toString(36).slice(-5); - 如果 Math.random() 返回 0.0 怎么办?

@x-ray,你会得到 "0" ;)

确切地。 ;) 如果 Math.random() 返回 0.5,则结果为 "0.i"。不确定是否还有其他边缘情况。只是想指出这不是问题的正确答案(来自 [a-zA-Z0-9] 的 5 个字符)。

@x-ray,我不会说这是正确的答案,我只是说这是上面@doubletap 答案的紧凑版本。我个人使用 (+new Date + Math.random()) 来防止这种情况。无论如何,谢谢你的注意。

为什么根本不使用 bota?我评论了其他答案,但使用这个测试用例你可以看到你将只使用 base64 必须提供的 64 个字符中的 14 个:[...new Set([...Array(100000)].map(()=>btoa(Math.random()).substr(0, 5)).join(""))].sort()

答7:

HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com

es6 spread operator 的较新版本:

[…Array(30)].map(() => Math.random().toString(36)[2]).join(‘’)

30 是一个任意数字,你可以选择任何你想要的令牌长度

36 是您可以传递给 numeric.toString() 的最大基数,这意味着所有数字和 az 小写字母

用于从如下所示的随机字符串中选择第三个索引:“0.mfbiohx64i”,我们可以取 0 之后的任何索引。

你能解释一下吗?尤其是为什么将 36 传递给 toString() 以及为什么选择第三个元素?

很好,但这个解决方案不包括 [AZ] 字符作为问题要求,只有 [a-z0-9]

@NahuelGreco 你可以做 [...Array(30)].map(() => Math.random().toString(36)[2]).join('').toUpperCase()

@tam.teixeira 我认为不,原始问题要求混合大写,每个字符必须从 [a-zA-Z0-9] 集中随机选择。这个答案不能满足这一点。

Array(30).fill().map(() => Math.random().toString(36).slice(2)).join('') 生成一个巨大的随机字符串

答8:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

像这样的东西应该工作

function randomString(len, charSet) {

charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

var randomString = '';

for (var i = 0; i < len; i++) {

var randomPoz = Math.floor(Math.random() * charSet.length);

randomString += charSet.substring(randomPoz,randomPoz+1);

}

return randomString;

}

使用默认字符集 [a-zA-Z0-9] 调用或发送您自己的:

var randomValue = randomString(5);

var randomValue = randomString(5, 'PICKCHARSFROMTHISSET');

可以在此处找到示例的变体:mediacollege.com/internet/javascript/number/random.html

还不如直接在 while 循环中减少 len

谢谢,我刚刚在下面发布了这个示例的咖啡脚本变体:stackoverflow.com/a/26682781/262379

如果这些要公开使用,那么您可能应该删除元音。熵少一点,但更安全,因为你不能生成任何可能冒犯人们的词。这就是我喜欢这个的原因,因为我可以发送自己的字符串。好工作。

请注意,在 Node 服务器上,它很简单:crypto.randomBytes(3).toString('hex')(例如,3 个字节给出 6 个字符)

答9:

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

函数随机字符串(L){ var s = ‘’; var randomchar = function() { var n = Math.floor(Math.random() * 62);如果 (n < 10) 返回 n; //1-10 if (n < 36) return String.fromCharCode(n + 55); //AZ return String.fromCharCode(n + 61); //az } while (s.length < L) s += randomchar();返回 s; } 控制台日志(随机字符串(5));

我最喜欢这个。您可以轻松修改以接受额外参数并仅返回数字、小写字母或大写字母。我认为不需要超压缩样式while(s.length< L) s+= randomchar();

while(L--) 也会这样做

最好使用更健壮的 'A'.charCodeAt(0) 而不是幻数 55(同样适用于 61)。特别是因为无论如何在我的平台上,返回的幻数是 65。该代码也将更好地自我记录。

我在这里为您的实现创建了一个缩小优化(小 46 个字节)的变体:stackoverflow.com/a/52412162

答10:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

随机字符串生成器(字母数字 | 字母 | 数字)

/** * 伪随机字符串生成器 * http://stackoverflow.com/a/27872144/383904 * 默认值:返回随机字母数字字符串 * * @param {Integer} len 所需长度 * @param {String} an可选(字母数字),“a”(字母),“n”(数字) * @return {String} */ function randomString(len, an) { an = an && an.toLowerCase(); var str = “”, i = 0, min = an == “a” ? 10:0,最大 = 一个 ==“n”? 10:62; for (; i++ < len;) { var r = Math.random() * (max - min) + min << 0; str += String.fromCharCode(r += r > 9 ? r < 36 ? 55 : 61 : 48); } 返回字符串; } console.log(randomString(10)); // ie: “4Z8iNQag9v” console.log(randomString(10, “a”)); // ie: “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 a String.fromCharCode( incremented 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 |

上表中的 conditional operation 逻辑:

rand += rand>9 ? ( rand<36 ? 55 : 61 ) : 48 ;

// rand += true ? ( true ? 55 else 61 ) else 48 ;

根据上面的解释,这是生成的字母数字片段:

函数 randomString(len) { var str = “”; // String result for (var i = 0; i < len; i++) { // 循环 len 次 var rand = Math.floor(Math.random() * 62); // 随机:0…61 var charCode = rand += rand > 9 ? (兰特 < 36 ? 55 : 61) : 48; // 获取正确的 charCode str += String.fromCharCode(charCode); // 将字符添加到 str } return str; // 所有循环完成后,返回连接的字符串 } console.log(randomString(10)); // 即:“7GL9F0ne6t”

或者,如果您愿意:

const randomString = (n, r=‘’) => { while (n–) r += String.fromCharCode((r=Math.random()*62|0, r+=r>9?(r<36 ?55:61):48));返回 r; };控制台日志(随机字符串(10))

打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!

由于我无法确定的原因,当我比较具有不同 ES 版本的两个应用程序的输出时,x.toString(36) --- 如上述答案中所使用的 --- 并没有可靠地生成相同的字符,并且这个函数为我解决了这个问题,因为它不使用 .toString()!

答11:

打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!

为了满足要求 [a-zA-Z0-9] 和 length=5 使用

对于浏览器:

btoa(Math.random().toString()).substr(10, 5);

对于 NodeJS:

Buffer.from(Math.random().toString()).toString("base64").substr(10, 5);

会出现小写字母、大写字母和数字。

(它与打字稿兼容)

我猜, Math.random() 可能会导致 base64 字符串的字符太少。

添加@Leif 评论,这只会生成 1-5 之间的数字,并且只有 52 个字母中的 19 个!(大写和小写)要测试,只需运行多次,Set 看看独特的字符,然后排序。一个班轮:[...new Set([...Array(100000)].map(()=>btoa(Math.random()).substr(5, 5)).join(""))].sort()

为什么我们在浏览器示例中需要 toString?

你是对的。不需要 toString()。但是因为我想做一些“它与打字稿兼容”。所以我就这样离开了。

Math.random().toString() 将只使用数字 0-9,这不是随机的。你不能只是 base64 它并期望它是随机的。您需要随机种子数据来创建随机输出。因此,此答案无法回答 OPs 问题。

原文链接:https://www.huntsbot.com/qa/Vd3W/generate-random-string-characters-in-javascript?lang=zh_CN&from=csdn

HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com

参考阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: