JavaScriptでランダムな文字列/文字を生成する

2009年08月29日に質問されました。  ·  閲覧回数 1.6M回  ·  ソース

Tom Lehman picture
2009年08月29日

セット[a-zA-Z0-9]からランダムに選択された文字で構成される5文字の文字列が必要です。

JavaScriptでこれを行うための最良の方法は何ですか?

回答

csharptest.net picture
2009年08月29日
2701

私はこれがあなたのために働くと思います:

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));
doubletap picture
2011年11月11日
2480

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

注:上記のアルゴリズムには、次の弱点があります。

  • 浮動小数点を文字列化するときに末尾のゼロが削除されるため、0〜6文字が生成されます。
  • これは、恐ろしく複雑な浮動小数点数を文字列化するために使用されるアルゴリズムに大きく依存します。 ( 「浮動小数点数を正確に印刷する方法」の論文を参照してください。)
  • Math.random()は、実装によっては、予測可能な(「ランダムに見える」が実際にはランダムではない)出力を生成する場合があります。 結果の文字列は、一意性または予測不可能性を保証する必要がある場合には適していません。
  • 均一にランダムで予測不可能な6文字が生成されたとしても、誕生日のパラドックスのため、約50,000個の文字列を生成しただけで重複が見られることが予想されます。 (sqrt(36 ^ 6)= 46656)
Thank you picture
2015年01月03日
539

Math.randomはこの種のことには良くあり

オプション1

このサーバー側で実行できる場合は、暗号モジュールを使用してください-

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

// "bb5dc8842ca31d4603d6aa11448d1654"

結果の文字列は、生成するランダムバイトの2倍の長さになります。 16進数にエンコードされた各バイトは2文字です。 20バイトは16進数の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 dec < 10
    ? '0' + String(dec)
    : dec.toString(16)
}

// 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を参照して

Silver Ringvee picture
2016年07月28日
192

短く、簡単で信頼性が高い

ここにある最高評価の回答のいくつかとは対照的に、正確に5つのランダムな文字を返します。

Math.random().toString(36).substr(2, 5);
amichair picture
2013年11月14日
162

これがdoubletapの優れた答えの改善です。 オリジナルには、ここで対処する2つの欠点があります。

まず、他の人が言及しているように、短い文字列または空の文字列(乱数が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です。しかし、説明したように、2番目の解決策は、ランダム性を追加することではなく、要求された文字列の長さをサポートすることです。したがって、大きな違いはありません。
  • 少なくともMath.random()によって返される結果が均等に分散されている限り、返されるすべての文字列は等しい確率で返されます(これは、いずれの場合も暗号強度のランダム性ではありません)。
  • サイズNのすべての可能な文字列が返されるわけではありません。 2番目の解決策では、これは明らかです(小さい文字列が単純に複製されているため)が、base-36への変換では、最後の数ビットが元のランダムビットの一部ではない可能性があるため、元の回答でもこれは当てはまります。 具体的には、Math.random()。toString(36)の結果を見ると、最後の文字が均等に分散されていないことがわかります。 繰り返しますが、ほとんどすべての場合、それは問題ではありませんが、短い文字列(N = 1など)が影響を受けないように、ランダムな文字列の最後ではなく最初から最後の文字列をスライスします。

更新:

これが私が思いついた他のいくつかの機能的なスタイルのワンライナーです。 これらは、上記のソリューションとは次の点で異なります。

  • それらは明示的な任意のアルファベットを使用します(より一般的で、大文字と小文字の両方を要求した元の質問に適しています)。
  • 長さNのすべての文字列は、返される確率が等しくなります(つまり、文字列には繰り返しが含まれません)。
  • これらは、toString(36)トリックではなく、map関数に基づいているため、より簡単で理解しやすくなっています。

だから、あなたが選んだアルファベットは

var s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

次に、これら2つは互いに同等であるため、より直感的な方を選択できます。

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

編集:

qubyteMartijnde Millianoが後者(kudos!)に似た解決策を思いついたようですが、どういうわけか見逃していました。 一見短く見えないので、誰かが本当にワンライナーを欲しがっている場合に備えて、とにかくここに残しておきます:-)

また、すべてのソリューションで「newArray」を「Array」に置き換えてさらに数バイトを削減しました。

Valentin Podkamennyi picture
2015年10月15日
144

slicesubstringよりも短いため、最もコンパクトなソリューションです。 文字列の末尾から減算すると、 random関数によって生成される浮動小数点記号を回避できます。

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

あるいは

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

更新: btoaメソッドを使用するもう1つのアプローチを追加しました:

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));
CaffGeek picture
2009年08月29日
102

このようなものが機能するはずです

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');
Or Duan picture
2017年11月26日
86

es6スプレッド演算子使用した新しいバージョン:

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

  • 30は任意の数値であり、任意のトークン長を選択できます
  • 36は、 numeric.toString()に渡すことができる最大の基数です。これは、すべての数値とaz小文字を意味
  • 2は、次のようなランダムな文字列から3番目のインデックスを選択するために使用されます: "0.mfbiohx64i"0.後に任意のインデックスを取得できます
kennebec picture
2009年08月29日
75

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));
Roko C. Buljan picture
2015年01月10日
66

ランダム文字列ジェネレータ(英数字|英数字|数値)

/**
 * 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出力に対して追加のチェックを使用していますが、理解を深めるために、基本事項(英数字のみ)に分解してみましょう。

  • 引数(ランダムな文字列の結果の望ましい長さ)を受け入れる関数を作成します
  • var str = "";ような空の文字列を作成して、ランダムな文字を連結します
  • ループ内で、 0から61までの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     |

上記の表条件付き操作ロジック

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