Câu hỏi Tạo chuỗi / ký tự ngẫu nhiên trong JavaScript


Tôi muốn một chuỗi gồm 5 ký tự gồm các ký tự được chọn ngẫu nhiên từ bộ [a-zA-Z0-9].

Cách tốt nhất để làm điều này với JavaScript là gì?


1160
2017-08-28 21:14


gốc


Cảnh báo: Không có câu trả lời nào có true-random kết quả! Họ chỉ là pseudo-random. Khi sử dụng chuỗi ngẫu nhiên để bảo vệ hoặc bảo mật, đừng sử dụng bất kỳ chuỗi nào trong số chúng !!! Hãy thử một trong những api này: random.org - Ron van der Heijden
Math.random (). ToString (36) .replace (/ [^ a-z] + / g, '') - Muaz Khan
Vui lòng đặt giải pháp vào một giải pháp. - chryss
Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5); - frieder
chú thích API ngẫu nhiên webcrypto HTML5 cung cấp ngẫu nhiên thực sự. - mikemaccana


Các câu trả lời:


Tôi nghĩ rằng điều này sẽ làm việc cho bạn:

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



Điều này là tốt cho các chuỗi ngắn, nhưng hãy cẩn thận, sử dụng += trên các chuỗi như thế này làm cho nó có hành vi O (n ^ 2). Nếu bạn muốn tạo chuỗi dài hơn, bạn nên tạo một mảng các ký tự riêng lẻ và kết hợp chúng với nhau ở cuối. - dan_waterworth
@dan_waterworth Nó có lẽ không quan trọng trong hầu hết bất kì trường hợp: codinghorror.com/blog/2009/01/… - Alex Reece
@dan_waterworth, Trên thực tế, += thường nhanh hơn vì một số lý do, thậm chí được sử dụng trong vòng lặp - jsperf.com/join-vs-concatenation - Konrad Borowski
@JonathanPaulson Chỉ cho tôi những con số. Xem nhận xét trước đó có liên kết jsperf hoặc jsperf.com/sad-tragedy-of-microoptimizationhoặc là sitepen.com/blog/2008/05/09/string-performance-an-analysis vv Ngoài ra, câu hỏi này chỉ liên quan đến 5 nối. - Alex Reece
Tôi đã sửa chữa - Jonathan Paulson


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

1729
2017-11-10 18:12



Math.random().toString(36).substr(2, 5), bởi vì .substring(7) khiến nó dài hơn 5 ký tự. Toàn điểm, vẫn còn! - dragon
@Scoop The toString phương pháp của một loại số trong javascript có một tham số tùy chọn để chuyển đổi số thành một cơ sở nhất định. Ví dụ: nếu bạn vượt qua hai, bạn sẽ thấy số của mình được biểu thị bằng nhị phân. Tương tự như hex (base 16), base 36 sử dụng các chữ cái để biểu thị các chữ số vượt quá 9. Bằng cách chuyển đổi một số ngẫu nhiên thành cơ sở 36, bạn sẽ kết thúc với một loạt các chữ cái và số ngẫu nhiên. - Chris Baker
Trông đẹp nhưng trong vài trường hợp, nó tạo ra chuỗi rỗng! Nếu trả về ngẫu nhiên 0, 0,5, 0,25, 0,125 ... sẽ dẫn đến chuỗi rỗng hoặc ngắn. - gertas
@gertas Điều này có thể tránh được bằng cách (Math.random() + 1).toString(36).substring(7); - George Reith
Guy, điều này gần như vô dụng. Chạy nó chỉ 1000000 lần và bạn thường nhận được khoảng 110000 lần xuất hiện lặp lại: var values ​​= {}, i = 0, duplicateCount = 0, val; trong khi (i <1000000) {val = Math.random (). toString (36) .substring (7); if (values ​​[val]) {duplicateCount ++; } giá trị [val] = 1; i ++; } console.log ("TOTAL DUPLICATES", duplicateCount); - hacklikecrack


Math.random là xấu cho loại điều

lựa chọn 1

Nếu bạn có thể làm điều này máy chủ-side, chỉ cần sử dụng crypto mô-đun

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

// "bb5dc8842ca31d4603d6aa11448d1654"

Chuỗi kết quả sẽ dài gấp đôi các byte ngẫu nhiên mà bạn tạo ra; mỗi byte được mã hóa thành hex là 2 ký tự. 20 byte sẽ là 40 ký tự của hex.


Lựa chọn 2

Nếu bạn phải làm điều này khách hàng-side, có lẽ thử mô-đun uuid

var uuid = require("uuid");
var id = uuid.v4();

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

Tùy chọn 3

Nếu bạn phải làm điều này khách hàngvà bạn không cần phải hỗ trợ các trình duyệt cũ, bạn có thể làm điều đó mà không cần phụ thuộc

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



Lưu ý rằng đối với UUID phiên bản 4, không phải tất cả các ký tự đều là ngẫu nhiên. Từ Wikipedia: "UUID phiên bản 4 có dạng xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx trong đó x là bất kỳ chữ số thập lục phân nào và y là một trong 8, 9, A hoặc B". (en.wikipedia.org/wiki/…) - wmassingham
@ wmassingham, tôi không chắc chắn tôi hiểu mục đích của bình luận của bạn. Bạn có nghĩa là để ngụ ý một cái gì đó mối quan tâm của sự độc đáo do một số ký tự cố định trong một uuid v4? - user633183
Chính xác. Trong khi UUID là tốt cho việc gán một ID cho một thứ, việc sử dụng nó như là một chuỗi các ký tự ngẫu nhiên không phải là một ý tưởng tuyệt vời cho lý do này (và có lẽ khác). - wmassingham
Tôi nghĩ điều này xứng đáng được nhiều upvotes hơn - DucDigital
Không cần .map() trong Tùy chọn 3. Array.from(arr, dec2hex).join('') === Array.from(arr).map(dec2hex).join(''). Cảm ơn bạn đã giới thiệu cho tôi những tính năng này :-) - Fred Gandt


Đây là một cải tiến về câu trả lời xuất sắc của doubletap. Bản gốc có hai nhược điểm được đề cập ở đây:

Đầu tiên, như những người khác đã đề cập, nó có một xác suất nhỏ của sản xuất dây ngắn hoặc thậm chí một chuỗi rỗng (nếu số ngẫu nhiên là 0), có thể phá vỡ ứng dụng của bạn. Đây là một giải pháp:

(Math.random().toString(36)+'00000000000000000').slice(2, N+2)

Thứ hai, cả bản gốc và giải pháp trên đều giới hạn kích thước chuỗi N đến 16 ký tự. Sau đây sẽ trả về một chuỗi có kích thước N cho bất kỳ N (nhưng lưu ý rằng việc sử dụng N> 16 sẽ không làm tăng tính ngẫu nhiên hoặc giảm xác suất va chạm):

Array(N+1).join((Math.random().toString(36)+'00000000000000000').slice(2, 18)).slice(0, N)

Giải trình:

  1. Chọn một số ngẫu nhiên trong phạm vi [0,1), tức là giữa 0 (bao gồm) và 1 (độc quyền).
  2. Chuyển đổi số thành chuỗi cơ sở-36, tức là sử dụng các ký tự 0-9 và a-z.
  3. Pad với số không (giải quyết vấn đề đầu tiên).
  4. Cắt giảm hàng đầu '0.' tiền tố và số không thừa.
  5. Lặp lại chuỗi đủ số lần để có ít nhất N ký tự trong đó (bằng cách tham gia các chuỗi trống bằng chuỗi ngẫu nhiên ngắn hơn được sử dụng làm dấu phân tách).
  6. Cắt chính xác N ký tự khỏi chuỗi.

Suy nghĩ thêm:

  • Giải pháp này không sử dụng chữ hoa, nhưng trong hầu như tất cả các trường hợp (không có ý định chơi chữ) nó không quan trọng.
  • Độ dài chuỗi tối đa tại N = 16 trong câu trả lời ban đầu được đo bằng Chrome. Trong Firefox nó là N = 11. Nhưng như đã giải thích, giải pháp thứ hai là hỗ trợ bất kỳ độ dài chuỗi được yêu cầu, không phải về việc thêm ngẫu nhiên, do đó, nó không tạo ra nhiều sự khác biệt.
  • Tất cả các chuỗi được trả lại đều có xác suất bằng nhau được trả về, ít nhất là khi kết quả trả về bởi Math.random () được phân bố đều (đây không phải là ngẫu nhiên cường độ mã hóa, trong mọi trường hợp).
  • Không phải tất cả các chuỗi có thể có kích thước N có thể được trả lại. Trong giải pháp thứ hai, điều này là hiển nhiên (vì chuỗi nhỏ hơn đơn giản được nhân bản), nhưng cũng trong câu trả lời ban đầu điều này là đúng vì trong chuyển đổi thành base-36, một vài bit cuối có thể không là một phần của các bit ngẫu nhiên ban đầu. Cụ thể, nếu bạn nhìn vào kết quả của Math.random (). ToString (36), bạn sẽ nhận thấy ký tự cuối cùng không được phân bố đều. Một lần nữa, trong hầu hết mọi trường hợp, nó không quan trọng, nhưng chúng ta cắt chuỗi cuối cùng từ đầu chứ không phải là kết thúc của chuỗi ngẫu nhiên sao cho các chuỗi ngắn (ví dụ: N = 1) không bị ảnh hưởng.

Cập nhật:

Dưới đây là một vài phong cách chức năng khác một lớp lót tôi đã đưa ra. Chúng khác với giải pháp ở trên trong đó:

  • Họ sử dụng một bảng chữ cái tùy ý rõ ràng (chung chung hơn, và phù hợp với câu hỏi ban đầu được yêu cầu cho cả chữ hoa và chữ thường).
  • Tất cả các chuỗi có độ dài N đều có xác suất bằng nhau được trả lại (tức là các chuỗi không chứa các lần lặp lại).
  • Chúng dựa trên một hàm bản đồ, chứ không phải là thủ thuật toString (36), điều này khiến chúng trở nên đơn giản và dễ hiểu hơn.

Vì vậy, nói rằng bảng chữ cái của bạn lựa chọn là

var s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

Sau đó, hai cái này tương đương với nhau, vì vậy bạn có thể chọn cái nào trực quan hơn với bạn:

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

Chỉnh sửa:

Tôi có vẻ như qubyte và Martijn de Milliano đã đưa ra các giải pháp tương tự như sau (kudo), mà tôi bằng cách nào đó đã bỏ lỡ. Vì họ không nhìn ngắn như trong nháy mắt, tôi sẽ để nó ở đây anyway trong trường hợp ai đó thực sự muốn một lót :-)

Ngoài ra, thay thế 'new Array' bằng 'Array' trong tất cả các giải pháp để cạo bỏ thêm một vài byte.


129
2017-11-13 21:18



Tại sao không chỉ thêm 1? (Math.random()+1).toString(36).substring(7); - emix
Bởi vì việc thêm 1 không giải quyết được một trong hai vấn đề được thảo luận ở đây. Ví dụ, (1) .toString (36) .substring (7) tạo ra một chuỗi rỗng. - amichair
Sử dụng Math.random().toString(36).substring(2,7) đưa ra kết quả mong đợi giống như .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
Điều này thật tuyệt vời, nhưng khi được thực hiện trong Firefox với N = 16, thì 6 chữ số cuối cùng kết thúc bằng không ... (Nhưng nó thỏa mãn mong muốn của OP cho 5 ký tự ngẫu nhiên). - Edward Newell


Ngắn gọn, dễ dàng và đáng tin cậy

Trả về chính xác 5 ký tự ngẫu nhiên, trái ngược với một số câu trả lời được đánh giá hàng đầu được tìm thấy ở đây.

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

126
2017-07-27 20:24



+10 cho giải pháp thông minh! - Jan Sverre
giải pháp đơn giản nhất. (++1)++ - Muhammad Hassan
Chuyện gi xảy ra nêu Math.random().toString(36) trả về một số có ít hơn 5 ký tự? - Michael Litvin
Để tránh nhận chuỗi rỗng trong trường hợp Math.random () trả về 0, bạn có thể sử dụng function getRandomString() { var result = ''; while (!result) result = Math.random().toString(36).substring(2); return result; }; - mikep
@rinogo Math.random () có thể trả về 0 nhưng không phải 1 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - mikep


Một cái gì đó như thế này sẽ làm việc

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

Gọi bằng bộ ký tự mặc định [a-zA-Z0-9] hoặc tự gửi:

var randomValue = randomString(5);

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

81
2017-08-28 21:28



Một biến thể của ví dụ ở đây có thể được tìm thấy ở đây: mediacollege.com/internet/javascript/number/random.html - David
cũng có thể chỉ giảm len trực tiếp trong một while vòng lặp - drzaus
Cảm ơn, tôi vừa đăng dưới đây một biến thể coffeescript của ví dụ này: stackoverflow.com/a/26682781/262379 - Dinis Cruz
Nếu những điều này sẽ được sử dụng công khai, thì có lẽ bạn nên loại bỏ các nguyên âm. Một chút ít entropy, nhưng an toàn hơn nhiều khi bạn không thể tạo ra bất kỳ từ nào có thể xúc phạm mọi người. Đó là lý do tại sao tôi thích điều này, vì tôi có thể gửi chuỗi ký tự của riêng mình. Làm tốt lắm. - Nate Bunney
câu trả lời đó đã giúp tôi cảm ơn :) - 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 vì không bao gồm danh sách ký tự. :) - TinkerTank
Tôi thích điều này là tốt nhất. Bạn có thể dễ dàng sửa đổi để chấp nhận các thông số bổ sung và chỉ trả về số, dấu giảm hoặc mũ. Tôi không nghĩ phong cách siêu nén là cần thiết while(s.length< L) s+= randomchar(); - mastaBlasta
Cũng thế while(L--) sẽ làm điều đó - vsync
Đây là mã tốt nhất hiện có ngay bây giờ - Amrut
Tốt hơn để sử dụng mạnh mẽ hơn 'A'.charCodeAt(0) thay vì số ma thuật 55 (và tương tự như vậy cho 61). Đặc biệt kể từ đó, trên nền tảng của tôi, số ma thuật trả về là 65. Mã đó cũng sẽ tự tài liệu tốt hơn. - Grumdrig


Giải pháp nhỏ gọn nhất, bởi vì slice ngắn hơn substring. Trừ từ cuối chuỗi cho phép tránh biểu tượng dấu chấm động được tạo ra bởi random chức năng:

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

hoặc thậm chí

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

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

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


49
2017-10-15 11:11





Trình tạo chuỗi ngẫu nhiên (Alpha-Numeric | Alpha | Numeric)

/**
 * RANDOM STRING GENERATOR
 *
 * Info:      http://stackoverflow.com/a/27872144/383904
 * Use:       randomString(length [,"A"] [,"N"] );
 * Default:   return a random alpha-numeric string
 * Arguments: If you use the optional "A", "N" flags:
 *            "A" (Alpha flag)   return random a-Z string
 *            "N" (Numeric flag) return random 0-9 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;
}
randomString(10);        // "4Z8iNQag9v"
randomString(10, "A");   // "aUkZuHNcWw"
randomString(10, "N");   // "9055739230"

Chúc vui vẻ. bản trình diễn jsBin


Trong khi ở trên sử dụng kiểm tra bổ sung cho đầu ra mong muốn (A / N, A, N), chúng ta hãy chia nhỏ nó thành các yếu tố cần thiết (Alpha-Numeric only) để hiểu rõ hơn:

  • Tạo một hàm chấp nhận một đối số (độ dài mong muốn của kết quả Chuỗi ngẫu nhiên)
  • Tạo một chuỗi rỗng như var str = ""; ghép các ký tự ngẫu nhiên
  • Bên trong một vòng lặp tạo một rand số chỉ mục từ 0 đến 61 (0..9 + A..Z + a..z = 62)
  • Tạo một logic logic có điều kiện đến Điều chỉnh / sửa rand (vì nó là 0,,61) tăng nó bằng một số (xem ví dụ bên dưới) để lấy lại quyền CharCode số và ký tự liên quan.
  • Bên trong vòng lặp nối với str một String.fromCharCode( incremented rand )

Hãy hình dung Bảng ký tự và của họ các dãy:

_____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 ) đưa ra một phạm vi từ 0..61 (những gì chúng tôi cần). Cách sửa (tăng) ngẫu nhiên để có được chính xác phạm vi mã mã?

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

Các hoạt động có điều kiện logic từ bảng trên:

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

Nếu bạn làm theo lời giải thích ở trên, bạn sẽ có thể tạo ra điều này đoạn mã alpha-số:

bản trình diễn jsBin

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) ); // "7GL9F0ne6t"

Hoặc nếu bạn sẽ:

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

40
2018-01-10 02:09





Cách đơn giản nhất là:

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

Điều này tạo ra các chuỗi ngẫu nhiên gồm 5 ký tự dựa trên thời gian hiện tại. Đầu ra mẫu là 4mtxjhoặc là 4mv90hoặc là 4mwp1

Vấn đề với điều này là nếu bạn gọi nó hai lần trong cùng một giây, nó sẽ tạo ra cùng một chuỗi.

Cách an toàn hơn là:

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

Điều này sẽ tạo ra một chuỗi ngẫu nhiên 4 hoặc 5 ký tự, luôn khác nhau. Kết quả ví dụ giống như 30jzmhoặc là 1r591hoặc là 4su1a

Trong cả hai cách phần đầu tiên tạo ra một số ngẫu nhiên. Các .toString(36) một phần đúc số tới đại diện base36 (alphadecimal) của nó.


28
2018-03-11 21:43



Tôi không hoàn toàn chắc chắn làm thế nào điều này trả lời câu hỏi; Đây là câu hỏi 7 năm tuổi với nhiều câu trả lời hợp lệ. Nếu bạn chọn để cung cấp một câu trả lời mới, bạn nên thực sự chăm sóc thêm để đảm bảo rằng câu trả lời của bạn được giải thích và tài liệu. - Claies
Nếu bạn sử dụng Date, tại sao bạn không sử dụng nó như: (+new Date).toString(36) - seniorpreacher
Tôi thích giải pháp số ngẫu nhiên của bạn nhưng 9e6 chỉ cung cấp 9 triệu khả năng trên 60,4 triệu khả năng cho 5 chữ số (36 ^ 5) để bạn có thể thay thế bằng (0|Math.random()*6.04e7).toString(36) để trang trải nó. - Le Droid
Tôi muốn một chuỗi ngẫu nhiên dài với một thói quen ngắn nhất có thể (cho một bản demo mã) mà không cần phải được mã hóa tuyệt vời, chỉ cần sản xuất một số hình ảnh ngẫu nhiên đẹp "lông tơ". Tôi thích câu trả lời này là tốt nhất (câu thứ 2 của bạn), vì vậy cảm ơn bạn. Hai xu của tôi: Tôi có thể đánh bại nó cho sự thiếu hụt với một phím tắt ít hơn, và nó thường sẽ tạo ra 13 ký tự ngẫu nhiên (không có dấu chấm): (Math.random()*1e20).toString(36). - Andrew Willems
một điều tôi có với câu trả lời này là nó sẽ không sử dụng [A-Z] xảy ra trong câu hỏi ban đầu. - user.friendly


Phiên bản mới hơn với es6  nhà điều hành lan truyền:

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

  • Các 30 là số tùy ý, bạn có thể chọn bất kỳ độ dài mã thông báo nào bạn muốn
  • Các 36 là số tổng hợp tối đa bạn có thể chuyển đến numeric.toString (), có nghĩa là tất cả số và chữ thường a-z
  • Các 3 được sử dụng để chọn số thứ 3 từ chuỗi ngẫu nhiên trông giống như sau: "0.mfbiohx64i", chúng tôi có thể lấy bất kỳ chỉ số nào sau 0.

24
2017-11-26 13:17



Bạn có thể giải thích? Đặc biệt là tại sao bạn vượt qua 36 đến toString () và tại sao bạn chọn yếu tố thứ 3? - vuza
@vuza được cập nhật với nhiều giải thích hơn - Or Duan