题 在JavaScript中生成随机字符串/字符


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

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


1160
2017-08-28 21:14


起源


警告:没有答案有 true-random 结果!它们只是 pseudo-random。使用随机字符串进行保护或安全时,请勿使用任何字符串!尝试其中一个api: random.org - Ron van der Heijden
Math.random()。toString(36).replace(/ [^ a-z] + / g,'') - Muaz Khan
请将解决方案放入解决方案中。 - chryss
Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5); - frieder
注意 HTML5 webcrypto随机性API 提供真正的随机性。 - mikemaccana


答案:


我认为这对你有用:

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;
}

console.log(makeid());


1648
2017-08-28 21:21



这适用于短字符串,但请注意,使用 += 在像这样的字符串上导致它具有O(n ^ 2)行为。如果要创建更长的字符串,则应创建单个字符的数组,并在最后将它们连接在一起。 - dan_waterworth
@dan_waterworth几乎没关系 任何 案件: codinghorror.com/blog/2009/01/... - Alex Reece
@dan_waterworth,实际上, += 由于某些原因通常更快,甚至在循环中使用 - jsperf.com/join-vs-concatenation - Konrad Borowski
@JonathanPaulson 告诉我数字。使用jsperf链接或参见上一条评论 jsperf.com/sad-tragedy-of-microoptimization 要么 sitepen.com/blog/2008/05/09/string-performance-an-analysis 此外,这个问题只涉及5个连接。 - Alex Reece
我有所纠正 - Jonathan Paulson


Math.random().toString(36).substring(7);

1729
2017-11-10 18:12



Math.random().toString(36).substr(2, 5)因为 .substring(7) 导致它超过5个字符。满分,还在! - dragon
@Scoop toString javascript中数字类型的方法采用可选参数将数字转换为给定的基数。例如,如果你传递两个,你会看到你的数字用二进制表示。类似于十六进制(基数16),基数36使用字母来表示超过9的数字。通过将随机数转换为基数36,您将得到一堆看似随机的字母和数字。 - Chris Baker
看起来很漂亮,但在少数情况下会产生空字符串!如果随机返回0,0.5,0.25,0.125 ......将导致空或短字符串。 - gertas
@gertas这可以避免 (Math.random() + 1).toString(36).substring(7); - George Reith
盖伊,这几乎没用。运行它只有1000000次,你通常会重复出现110000次:var values = {},i = 0,duplicateCount = 0,val; while(i <1000000){val = Math.random()。toString(36).substring(7); if(values [val]){duplicateCount ++; } values [val] = 1;我++; } console.log(“TOTAL DUPLICATES”,duplicateCount); - hacklikecrack


的Math.random 对这种事情不好

选项1

如果你能做到这一点 服务器只是,使用 加密 模

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
function dec2hex (dec) {
  return ('0' + dec.toString(16)).substr(-2)
}

// 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"


242
2018-01-02 19:18



请注意,对于版本4 UUID,并非所有字符都是随机的。来自维基百科:“版本4 UUID的格式为xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,其中x是任何十六进制数字,y是8,9,A或B之一”。 (en.wikipedia.org/wiki/...) - wmassingham
@wmassingham,我不确定我理解你评论的目的。你的意思是暗示某些因v4 uuid中某些固定字符引起的唯一性问题吗? - user633183
究竟。虽然UUID可以为一个东西分配一个ID,但是将它作为一串随机字符使用对于这个(可能是其他的)原因并不是一个好主意。 - wmassingham
我认为这应该得到更多的赞成 - DucDigital
没必要 .map() 在备选方案3中。 Array.from(arr, dec2hex).join('') === Array.from(arr).map(dec2hex).join('')。感谢您向我介绍这些功能:-) - Fred Gandt


这是一个改进 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)

说明:

  1. 选择范围[0,1)中的随机数,即在0(包括)和1(不包括)之间。
  2. 将数字转换为base-36字符串,即使用字符0-9和a-z。
  3. 用零填充(解决第一个问题)。
  4. 切掉领先的'0'前缀和额外的填充零。
  5. 重复该字符串足够的时间,其中至少包含N个字符(通过使用用作分隔符的较短随机字符串连接空字符串)。
  6. 从字符串中精确切割N个字符。

进一步思考:

  • 这个解决方案不使用大写字母,但几乎在所有情况下(没有双关语)都无关紧要。
  • 在Chrome中测量原始答案中N = 16的最大字符串长度。在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',以减少更多字节。


129
2017-11-13 21:18



为什么不加1呢? (Math.random()+1).toString(36).substring(7); - emix
因为添加1并不能解决此处讨论的两个问题。例如,(1).toString(36).substring(7)生成一个空字符串。 - amichair
运用 Math.random().toString(36).substring(2,7) 给出一个更像是的预期结果 .substring(2, n+2) - Joseph Rex
Array.apply(null, {length: 5}).map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('') - Muhammad Umer
这很棒,但是当在N = 16的Firefox中执行时,最后的~6个数字最终为零......(但它确实满足了OP对5个随机字符的期望。) - Edward Newell


简短,轻松,可靠

返回5个随机字符,而不是这里找到的一些最受欢迎的答案。

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

126
2017-07-27 20:24



+10聪明的解决方案! - Jan Sverre
最简单的解决方案 (++1)++ - Muhammad Hassan
如果 Math.random().toString(36) 返回少于5个字符的数字? - Michael Litvin
为了避免在Math.random()返回0的情况下获取空字符串,您可以使用 function getRandomString() { var result = ''; while (!result) result = Math.random().toString(36).substring(2); return result; }; - mikep
@rinogo Math.random()可以返回0而不是1 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - mikep


这样的事情应该有效

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');

81
2017-08-28 21:28



这里有一个例子的变体可以在这里找到: mediacollege.com/internet/javascript/number/random.html - David
也许只是减少 len 直接在一个 while 循环 - drzaus
谢谢,我刚刚在下面发布了这个示例的coffeescript变体: stackoverflow.com/a/26682781/262379 - Dinis Cruz
如果这些将被公开使用,那么你应该删除元音。熵少一点,但更安全,因为你不能产生任何可能冒犯人的话。这就是为什么我喜欢这个,因为我可以发送我自己的字符串。做得好。 - Nate Bunney
那个答案帮我谢谢:) - Piyush Patel


function randomstring(L) {
  var s = '';
  var randomchar = function() {
    var n = Math.floor(Math.random() * 62);
    if (n < 10) return n; //1-10
    if (n < 36) return String.fromCharCode(n + 55); //A-Z
    return String.fromCharCode(n + 61); //a-z
  }
  while (s.length < L) s += randomchar();
  return s;
}
console.log(randomstring(5));


61
2017-08-29 02:41



+1不包括字符列表。 :) - TinkerTank
我最喜欢这个。您可以轻松修改以接受额外参数并仅返回nums,lowers或caps。我不认为超压缩风格是必要的 while(s.length< L) s+= randomchar(); - mastaBlasta
也 while(L--) 会做的 - vsync
这是目前最好的代码 - Amrut
更好地使用更强大 'A'.charCodeAt(0) 而不是神奇的数字 55 (同样适用于 61)。特别是因为,无论如何,在我的平台上,返回的神奇数字是 65。该代码也将更好地自我记录。 - Grumdrig