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


1777

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

用JavaScript做到这一点的最佳方法是什么?


48
警告:没有答案true-random!他们只是pseudo-random。将随机字符串用于保护或安全性时,请勿使用其中任何一个!!!尝试以下一种api:random.org
罗恩·范·德·

48
Math.random()。toString(36).replace(/ [^ az] + / g,'')
Muaz Khan 2013年

13
请将该解决方案放入解决方案中。
chryss 2013年

214
Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
弗里德里希·

12
注意HTML5 webcrypto随机性API提供了真正的随机性。
mikemaccana

Answers:


2430

我认为这将为您工作:

function makeid(length) {
   var result           = '';
   var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
   var charactersLength = characters.length;
   for ( var i = 0; i < length; i++ ) {
      result += characters.charAt(Math.floor(Math.random() * charactersLength));
   }
   return result;
}

console.log(makeid(5));


117
这对于短字符串来说很好,但是请注意,+=在这样的字符串上使用会导致它具有O(n ^ 2)行为。如果要创建更长的字符串,则应创建一个由单个字符组成的数组,并在最后将它们连接在一起。
dan_waterworth 2012年

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

7
实际上,@ dan_waterworth +=由于某些原因通常会更快,甚至在循环内使用-jsperf.com/join-vs-concatenation
Konrad Borowski

18
@JonathanPaulson 告诉我这些数字。请参阅前面的注释以及jsperf链接或jsperf.com/sad-tragedy-of-microoptimizationsitepen.com/blog/2008/05/09/string-performance-an-analysis等。此外,此问题仅涉及5个串联。
亚历克斯·里斯

11
@codenamejames请不要在密码盐化中使用它。只是伪随机并不安全。假设您正在使用Node(如果您在客户端撒盐,我什至不知道从哪里开始),请crypto改用。
Hydrothermal

2330

let r = Math.random().toString(36).substring(7);
console.log("random", r);

注意:以上算法具有以下缺点:

  • 由于在对浮点进行字符串化时会删除尾随零,因此它将生成0到6个字符之间的任意位置。
  • 这在很大程度上取决于用于对浮点数进行字符串化的算法,该算法极其复杂。(请参阅论文“如何准确打印浮点数”。)
  • Math.random()根据实现的不同,可能会产生可预测的(“看上去很随机”但不是真正随机的)输出。当您需要保证唯一性或不可预测性时,结果字符串不适合。
  • 即使它产生了6个均匀随机且不可预测的字符,由于生日悖论,您也可以期望仅生成大约50,000个字符串后看到重复项。(sqrt(36 ^ 6)= 46656)

276
Math.random().toString(36).substr(2, 5),因为.substring(7)长度超过5个字符。满分!

81
@Scoop toStringjavascript中数字类型的方法采用可选参数,以将数字转换为给定的底数。例如,如果您传递两个,则您将看到以二进制表示的数字。与十六进制(基数16)相似,基数36使用字母来表示9以外的数字。通过将随机数转换为基数36,您将得到一系列看似随机的字母和数字。
克里斯·贝克

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

67
@gertas可以避免(Math.random() + 1).toString(36).substring(7);
乔治·

84
伙计,这实际上是没有用的。运行它仅1000000次,通常会出现110000次重复出现:var values = {},i = 0,duplicateCount = 0,val; 而(i <1000000){val = Math.random()。toString(36).substring(7); if(values [val]){repeatCount ++; } values [val] = 1; i ++; } console.log(“ TOTAL DUPLICATES”,repeatCount);
hacklikecrack 2013年

463

Math.random对这种事情不利

选项1

如果您能够在服务器端执行此操作,则只需使用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
// i.e. 0-255 -> '00'-'ff'
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"


有关更多信息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


4
究竟。尽管UUID可以为事物分配ID,但出于这个(可能还有其他)原因,将其用作一串随机字符并不是一个好主意。
wmassingham

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

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

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

1
require模块不是只能在服务器端使用吗?
aJetHorn19年

173

简短,简单且可靠

返回恰好5个随机字符,与此处找到的一些评价最高的答案相反。

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

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

3
好吧,这是@Aperçu提出的有趣的指控,我并不是说我发明了该解决方案,但多年来我一直在我的项目中使用它。它与您提到的评论无关。而且我非常确定,在适当的地方,最重要的信息就是最有用的信息,即使它已经存在于其他位置。幸运的是,似乎至少有51个人找到了此答案有用,欢迎您!
Silver Ringvee

3
为了避免在Math.random()返回0的情况下获取空字符串,您可以使用function getRandomString() { var result = ''; while (!result) result = Math.random().toString(36).substring(2); return result; };
mikep

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

6
我运行了此代码1,000,000,000次,但仍然没有得到一个空字符串:jsfiddle.net/mtp5730r我会说您很安全地得到一个空字符串。
MacroMan '18

157

这是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. 将数字转换为以36为基数的字符串,即使用字符0-9和az。
  3. 用零填充(解决第一个问题)。
  4. 删除开头的“ 0”。前缀和额外的填充零。
  5. 重复该字符串足够的次数,以使其至少包含N个字符(通过将空字符串与较短的随机字符串用作分隔符进行连接)。
  6. 从字符串中精确切出N个字符。

进一步的想法:

  • 此解决方案不使用大写字母,但是在几乎所有情况下(无双关语)都无关紧要。
  • 原始答案中N = 16时的最大字符串长度是在Chrome中测量的。在Firefox中,它的N =11。但是,如前所述,第二种解决方案是支持任何请求的字符串长度,而不是增加随机性,因此没有太大区别。
  • 至少就Math.random()返回的结果均匀分布而言,所有返回的字符串都有相等的返回概率(无论如何,这不是密码强度随机性)。
  • 并非所有可能的大小为N的字符串都将返回。在第二种解决方案中,这是显而易见的(因为只复制了较小的字符串),但在原始答案中也是如此,因为在转换为base-36时,最后几位可能不是原始随机位的一部分。具体来说,如果查看Math.random()。toString(36)的结果,您会注意到最后一个字符分布不均匀。同样,在几乎所有情况下都没有关系,但是我们从随机字符串的开头而不是结尾处切片最后一个字符串,这样短字符串(例如N = 1)不会受到影响。

更新:

这是我想到的其他几个功能样式的单线纸。它们与上述解决方案的不同之处在于:

  • 他们使用一个明确的任意字母(更通用,并且适用于要求同时使用大写和小写字母的原始问题)。
  • 所有长度为N的字符串都有相等的返回概率(即字符串不包含重复)。
  • 它们基于映射函数,而不是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('');

编辑:

好像qubyteMartijn de Milliano提出了与后者类似的解决方案(赞!),我不知为何错过了。由于它们看起来并不那么短,所以我还是把它留在这里,以防有人真的想要单线:-)

同样,在所有解决方案中都将“ new Array”替换为“ Array”以节省更多字节。


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

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

使用Math.random().toString(36).substring(2,7)给出的预期结果更像是.substring(2, n+2)
Joseph Rex 2015年

Array.apply(null, {length: 5}).map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('')
穆罕默德·乌默尔

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

126

最紧凑的解决方案,因为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);

// Using Math.random and Base 36:
console.log(Math.random().toString(36).slice(-5));

// Using new Date and Base 36:
console.log((+new Date).toString(36).slice(-5));

// Using Math.random and Base 64 (btoa):
console.log(btoa(Math.random()).slice(0, 5));

// Using new Date and 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射线

@ x-ray,您会得到"0";)
Valentin Podkamennyi

2
究竟。;)如果Math.random()返回,0.5则结果为"0.i"。不知道是否还有其他情况。只是想指出这不是问题的正确答案([a-zA-Z0-9]中的5个字符)。
X射线

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

1
这个。我不知道为什么其他答案需要那么多代码
john ktejik

100

这样的事情应该工作

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


1
还不如干脆递减len直接在while
drzaus

谢谢,我刚刚在这个示例的Coffeescript版本下面发布了:stackoverflow.com/a/26682781/262379
Dinis Cruz

如果这些将要公开使用,那么您可能应该删除元音。熵少一些,但安全得多,因为您不会产生任何可能冒犯他人的单词。这就是为什么我喜欢这样,因为我可以发送自己的字符串。做得好。
Nate Bunney

非常顽固,为我工作,谢谢!
扎基·穆罕默德

73

带有es6 传播算子的较新版本:

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

  • 30是任意的号码,你可以选择你想要的任何标记长度
  • 36是最大基数数可以传递给numeric.toString() ,这意味着所有的数字和AZ小写字母
  • 2是用来接从它看起来像这样的随机字符串这是第3指标:"0.mfbiohx64i",我们可以采取任何索引后0.

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

5
这是最好的解决方案
战胜者

很好,但是此解决方案未按要求提供[AZ]字符,仅[a-z0-9]
Nahuel Greco

71

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


我最喜欢这个。您可以轻松地进行修改以接受额外的参数,并且仅返回num,lower或caps。我认为没有必要使用超压缩样式while(s.length< L) s+= randomchar();
mastaBlasta 2014年

3
while(L--)将这样做
vsync

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

我在此处创建了实现的优化优化版本(缩小了46个字节),方法如下:stackoverflow.com/a/52412162
Waruyama

调试@Waruyama的好运。那就是webpack的目的!
迪伦·沃森

61

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

/**
 * Pseudo-random string generator
 * http://stackoverflow.com/a/27872144/383904
 * Default: return a random alpha-numeric string
 * 
 * @param {Integer} len Desired length
 * @param {String} an Optional (alphanumeric), "a" (alpha), "n" (numeric)
 * @return {String}
 */
function randomString(len, an) {
  an = an && an.toLowerCase();
  var str = "",
    i = 0,
    min = an == "a" ? 10 : 0,
    max = an == "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);
  }
  return str;
}

console.log(randomString(10));      // i.e: "4Z8iNQag9v"
console.log(randomString(10, "a")); // i.e: "aUkZuHNcWw"
console.log(randomString(10, "n")); // i.e: "9055739230"


尽管以上内容针对所需的A / N,A,N输出使用了其他检查,但为了更好地理解,我们将其分解为基本内容(仅字母数字)。

  • 创建一个接受参数的函数(随机String结果的期望长度)
  • 创建一个空字符串var str = "";以连接随机字符
  • 在循环内创建一个rand0到61 索引号(0..9 + A..Z + a..z = 62)
  • 创建一个条件逻辑调整/固定rand(因为它是0..61),将其递增某个数字(请参见下面的示例),以获取正确的CharCode数字和相关的Character。
  • 循环内连接到str一个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     |

上表中的条件运算逻辑

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

根据上面的说明,这是生成的字母数字代码段

function randomString(len) {
  var str = "";                                // String result
  for (var i = 0; i < len; i++) {              // Loop `len` times
    var rand = Math.floor(Math.random() * 62); // random: 0..61
    var charCode = rand += rand > 9 ? (rand < 36 ? 55 : 61) : 48; // Get correct charCode
    str += String.fromCharCode(charCode);      // add Character to str
  }
  return str; // After all loops are done, return the concatenated string
}

console.log(randomString(10)); // i.e: "7GL9F0ne6t"

或者,如果您会:

const randomString = (n, r='') => {
  while (n--) r += String.fromCharCode((r=Math.random()*62|0, r+=r>9?(r<36?55:61):48));
  return r;
};

console.log(randomString(10))


33

最简单的方法是:

(new Date%9e6).toString(36)

这会根据当前时间生成5个字符的随机字符串。示例输出为4mtxjor 4mv904mwp1

问题是,如果您在同一秒钟两次调用它,它将生成相同的字符串。

比较安全的方法是:

(0|Math.random()*9e6).toString(36)

这将生成一个随机的4或5个字符的字符串,始终不同。示例输出类似于30jzm1r5914su1a

无论哪种方式,第一部分都会生成一个随机数。该.toString(36)部分将数字转换为以base36(字母十进制)表示的形式。


我不太确定这如何回答这个问题。这是一个已有7年历史的问题,已经有很多有效的答案。如果您选择提供一个新答案,则应格外小心,以确保您的答案得到了很好的解释和记录。
Claies 2015年

1
如果您使用日期,为什么不像这样使用它:(+new Date).toString(36)
seniorpreacher15年

我喜欢您的随机数解决方案,但9e6仅提供5位数(36 ^ 5)的6040万个数字中的900万个可能性,因此您可以用它代替它(0|Math.random()*6.04e7).toString(36)来覆盖它。
Le Droid

1
我想要一个较长的随机字符串,它带有一个尽可能短的例程(用于代码演示),不需要在密码学上令人惊奇,只需产生一些不错的随机视觉“绒毛”即可。我最喜欢这个答案(您的第二个答案),谢谢。我的两分钱:我可以用一个按键少打它急促,它通常会产生13个随机字符(无期限)(Math.random()*1e20).toString(36)
安德鲁·威廉姆斯

我对这个答案的疑惑是它不会使用[AZ],它恰好在原始问题中。
user.friendly

22

这是一些简单的衬板。更改new Array(5)以设置长度。

包含 0-9a-z

new Array(5).join().replace(/(.|$)/g, function(){return ((Math.random()*36)|0).toString(36);})

包含 0-9a-zA-Z

new Array(5).join().replace(/(.|$)/g, function(){return ((Math.random()*36)|0).toString(36)[Math.random()<.5?"toString":"toUpperCase"]();});

20

我知道每个人都已经做好了,但是我想尽可能以最轻便的方式(轻巧的代码而不是CPU)尝试一下:

function rand(length, current) {
  current = current ? current : '';
  return length ? rand(--length, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".charAt(Math.floor(Math.random() * 60)) + current) : current;
}

console.log(rand(5));

花费很多时间,但是我认为它确实显示了javascript的语法多么出色。


20
如果您要使代码简短,为什么要current = current ? current : '';在可以编写时编写current = current || ''
CaffGeek 2011年

9
因为我们在这里谈论微优化,所以我实际上建议在没有必要的情况下完全跳过变量分配:current || (current = '');
Thomas Heymann 2013年

在尝试使用“ nice”但资源浪费的递归算法时尝试微优化是没有道理的:-) for循环在Javascript中仍然是最好的,并且比递归花费了很多时间,直到在运行时的优化代码方面取得了很大的进步为止。
Mörre

17

如果你正在使用Lodash下划线,那么就这么简单:

var randomVal = _.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 5).join('');

6
Lodash使用_.sampleSize('asdfgh',5).join('')
marlo

2
这实际上不是一个好的解决方案,因为每个文档的每个字符都来自唯一索引。这意味着它不是真正随机的,因为没有字符可以/将不会重复。
random_user_name

16

为了满足要求[a-zA-Z0-9]并且长度= 5,请使用

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

将出现小写字母,大写字母和数字。


1
我猜想Math.random()可能导致base64字符串中的字符太少。
Leif

14

如果有人对一次性分配内存的单行(尽管不是为了格式化方便)感兴趣(但请注意,对于小字符串来说,这确实没有关系),这是如何做的:

Array.apply(0, Array(5)).map(function() {
    return (function(charset){
        return charset.charAt(Math.floor(Math.random() * charset.length))
    }('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'));
}).join('')

您可以替换5为所需字符串的长度。由于@AriyaHidayat在这篇文章的解决map没有工作所创造的稀疏阵列功能Array(5)


13
如果您将其格式化,则每个javascript程序都是一个“单一代码”
hacklikecrack 2013年

13

这是我创建的方法。
它将创建一个包含大写和小写字符的字符串。
另外,我还包含了将创建字母数字字符串的函数。

工作示例:
http : //jsfiddle.net/greatbigmassive/vhsxs/ (仅限字母)
http://jsfiddle.net/greatbigmassive/PJwg8/(字母数字)

function randString(x){
    var s = "";
    while(s.length<x&&x>0){
        var r = Math.random();
        s+= String.fromCharCode(Math.floor(r*26) + (r>0.5?97:65));
    }
    return s;
}

2015年7月升级
这样做是一样的,但是更有意义,并且包括所有字母。

var s = "";
while(s.length<x&&x>0){
    v = Math.random()<0.5?32:0;
    s += String.fromCharCode(Math.round(Math.random()*((122-v)-(97-v))+(97-v)));
}

使用此功能,您永远不会获得大于“ M”的大写字母或小于“ n”的小写字母。
erkanyildiz 2015年

真?哦!然后可能会对其进行更多测试。嗯,但是,由于它是一个随机字符串,我们并不真正在意其中的字母(只要它们是随机的),那么它仍然会按照我们想要的去做,这很重要,但是可以,它将提供一个升级,谢谢。
亚当

12

假设您使用underscorejs,则可以仅在两行中优雅地生成随机字符串:

var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var random = _.sample(possible, 5).join('');

6
这将使返回值具有所有唯一字符。同样,字符串的长度被限制为最大可能的var长度。
Yefu


10

快速改进的算法。不保证统一(见评论)。

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

2
很好的答案,但机率不统一。有62个可能的字符,并crypto.getRandomValues返回256个唯一值之一。因为256不除以62,所以最终得到字符AH的可能性会稍高。我认为最好的解决方案是做YouTube所做的事情,然后在字符集中添加2个其他字符(可能是-_)。无论如何,出色的工作-这个答案需要更多的爱:)
TeWu

添加-和_是一个好主意,因为它将为您提供完整的url安全的base64集
cowbert

8

回答“我需要随机字符串”问题(无论使用哪种语言)的问题实际上是每个解决方案都使用有缺陷的字符串长度基本规范。问题本身很少揭示为什么需要随机字符串,但是我会挑战您很少需要长度随机的字符串(例如8)。您总是需要一定数量的唯一字符串,例如,出于某些目的用作标识符。

获得严格唯一的字符串有两种主要方法:确定性(不是随机的)和存储/比较(繁琐的)。我们做什么?我们放弃了幽灵。我们代之以概率唯一性。也就是说,我们接受我们的字符串存在唯一性的风险(但很小)。在这里,了解碰撞概率很有帮助。

因此,我将不变的需求重新表述为需要一定数量的字符串,重复的风险很小。举一个具体的例子,假设您要生成500万个ID。您不想存储和比较每个新字符串,并且希望它们是随机的,因此您会承受重复的风险。例如,假设万亿重覆机会的风险小于1。那么,您需要多长的字符串?嗯,这个问题没有明确说明,因为它取决于所使用的字符。但更重要的是,它被误导了。您需要的是字符串熵的规范,而不是字符串的长度。熵可以直接与某些字符串中重复的概率相关。字符串长度不能。

这就是像EntropyString这样的库可以提供帮助的地方。要生成随机ID,该随机ID在500万个字符串中的重复概率少于1万亿分之一,请使用entropy-string

import {Random, Entropy} from 'entropy-string'

const random = new Random()
const bits = Entropy.bits(5e6, 1e12)

const string = random.string(bits)

“ 44hTNghjNHGGRHqH9”

entropy-string默认情况下使用32个字符的字符集。还有其他预定义的字符集,您也可以指定自己的字符。例如,生成具有与上述相同的熵但使用十六进制字符的ID:

import {Random, Entropy, charSet16} from './entropy-string'

const random = new Random(charSet16)
const bits = Entropy.bits(5e6, 1e12)

const string = random.string(bits)

“ 27b33372ade513715481f”

请注意,由于使用的字符集中的字符总数不同,字符串长度也有所不同。在指定数量的潜在字符串中重复的风险是相同的。字符串长度不是。最重要的是,重复的风险和潜在的字符串数是明确的。不再需要猜测字符串的长度。


7
function randomString (strLength, charSet) {
    var result = [];

    strLength = strLength || 5;
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    while (--strLength) {
        result.push(charSet.charAt(Math.floor(Math.random() * charSet.length)));
    }

    return result.join('');
}

这将是干净的。http://jsperf.com/ay-random-string也很快。


对我而言,它总是使用以下命令生成随机字符串strLength - 1:-/
xanderiel

3
从切换--strLengthstrLength--补丁对我来说。
xanderiel

7

您可以遍历一系列项并将其递归地添加到字符串变量中,例如,如果您需要随机DNA序列:

function randomDNA(len) {
  len = len || 100
  var nuc = new Array("A", "T", "C", "G")
  var i = 0
  var n = 0
  s = ''
  while (i <= len - 1) {
    n = Math.floor(Math.random() * 4)
    s += nuc[n]
    i++
  }
  return s
}

console.log(randomDNA(5));


6

我找不到同时支持小写和大写字符的干净解决方案。

仅支持小写字母:

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

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

Math.random().toString(36).substr(2, 5).split('').map(c => Math.random() < 0.5 ? c.toUpperCase() : c).join('');

更改5substr(2, 5)调整到你需要的长度。


6

一班轮:

Array(15).fill(null).map(() => Math.random().toString(36).substr(2)).join('')
// Outputs: 0h61cbpw96y83qtnunwme5lxk1i70a6o5r5lckfcyh1dl9fffydcfxddd69ada9tu9jvqdx864xj1ul3wtfztmh2oz2vs3mv6ej0fe58ho1cftkjcuyl2lfkmxlwua83ibotxqc4guyuvrvtf60naob26t6swzpil

为了使其更短,请将参数更改Array(15)为较小的值。例如:Array(4)
安德鲁

我真的很喜欢这种解决方案,简单明了。它正在生成0到1之间的15个随机数,生成十六进制,然后删除前两个字符。最后,它将所有这些合并在一起。
西西亚

5

这肯定可以工作

<script language="javascript" type="text/javascript">
function randomString() {
 var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
 var string_length = 8;
 var randomstring = '';
 for (var i=0; i<string_length; i++) {
  var rnum = Math.floor(Math.random() * chars.length);
  randomstring += chars.substring(rnum,rnum+1);
 }
 document.randform.randomfield.value = randomstring;
}
</script>

5

像这样的事情怎么样:Date.now().toString(36) 不是很随机,但是每次调用都简短而非常独特。


1
不幸的是,这并不是唯一的,因为Date.now()只有毫秒级的分辨率。例如,当以简单循环运行时,您会得到很多重复。for (let i = 0; i < 10; ++i) { console.log(Date.now().toString(36)); }
Nate

5

不区分大小写的字母数字字符:

function randStr(len) {
  let s = '';
  while (s.length < len) s += Math.random().toString(36).substr(2, len - s.length);
  return s;
}

// usage
console.log(randStr(50));

此功能的好处是您可以获取不同长度的随机字符串,并且可以确保字符串的长度。

区分大小写的所有字符:

function randStr(len) {
  let s = '';
  while (len--) s += String.fromCodePoint(Math.floor(Math.random() * (126 - 33) + 33));
  return s;
}

// usage
console.log(randStr(50));

自定义字符

function randStr(len, chars='abc123') {
  let s = '';
  while (len--) s += chars[Math.floor(Math.random() * chars.length)];
  return s;
}

// usage
console.log(randStr(50));
console.log(randStr(50, 'abc'));
console.log(randStr(50, 'aab')); // more a than b


这个答案更适合我的用例。如果可以var possible在接受的答案中添加一个赞,那将很酷,因此该函数的结果更具可配置性。
Denis.Sabolotni,

4

生成10个字符长的字符串。长度由参数设置(默认为10)。

function random_string_generator(len) {
var len = len || 10;
var str = '';
var i = 0;

for(i=0; i<len; i++) {
    switch(Math.floor(Math.random()*3+1)) {
        case 1: // digit
            str += (Math.floor(Math.random()*9)).toString();
        break;

        case 2: // small letter
            str += String.fromCharCode(Math.floor(Math.random()*26) + 97); //'a'.charCodeAt(0));
        break;

        case 3: // big letter
            str += String.fromCharCode(Math.floor(Math.random()*26) + 65); //'A'.charCodeAt(0));
        break;

        default:
        break;
    }
}
return str;
}

4

您可以使用coderain。这是一个根据给定模式生成随机代码的库。使用#作为大小写字母以及数字的占位符:

var cr = new CodeRain("#####");
console.log(cr.next());

还有其他占位符,例如A大写字母或9数字。

可能有用的是 .next()将始终为您带来独特的结果,因此您不必担心重复。

这是一个演示应用程序,它生成唯一的随机代码列表

全面披露:我是coderain的作者。


否否否-使用本机方法。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.