javascript - 重複なし - tostring(36)




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

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

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


ランダムな文字列ジェネレータ(アルファ数値|アルファ|数値)

/**
 * RANDOM STRING GENERATOR
 *
 * Info:      http://.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"

楽しむ。 jsBinデモ

上の例では、目的の(A / N、A、N)出力の追加チェックを使用していますが、 理解を深めるために必要不可欠なもの(Alpha-Numericのみ)

  • 引数(ランダムな文字列の結果の長さ)を受け入れる関数を作成する
  • var str = "";ような空の文字列を作成しますvar str = ""; ランダムな文字を連結する
  • ループ内で、 0から61までのrandインデックス番号を作成します (0..9 + A..Z + a..z = 62)
  • 右側のCharCode番号と関連するCharacterを取得するには、いくつかの数値(下記の例を参照)をインクリメントしてrand (0..61以降)を調整/修正するための条件付きロジックを作成します。
  • ループ内でstrString.fromCharCode( incremented rand )

Characterテーブルとその範囲を描きましょう:

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

上記の説明に従った場合、この英数字スニペットを作成することができます

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"

または、もしあなたが:

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

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

ここで見つかった上位の回答のいくつかとは対照的に、正確に5つのランダムな文字を返します。

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

#1答えのテストスクリプトです(ありがとう@ csharptest.net)

スクリプトはmakeid() 1 million回実行し、あなたが見ることができるように5は非常にユニークではありません。 charの長さを10にして実行すると、かなり信頼できます。 私は約50回それを走らせて、重複はまだ見ていない:-)

注:ノードスタックのサイズ制限は約400万を超えているので、これを5百万回実行することはできません。

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

ids ={}
count = 0
for (var i = 0; i < 1000000; i++) {
    tempId = makeid();
    if (typeof ids[tempId] !== 'undefined') {
        ids[tempId]++;
        if (ids[tempId] === 2) {
            count ++;
        }
        count++;
    }else{
        ids[tempId] = 1;
    }
}
console.log("there are "+count+ ' duplicate ids');

Underscoreを使用すると仮定すると、ただ2つの行でランダムな文字列をエレガントに生成することができます:

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

LodashまたはUnderscoreを使用している場合、それはとても簡単です:

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

「私はランダムな文字列が必要です」という質問に対する回答の問題は、実際にはすべての解決策が文字列の長さに関する一次仕様の欠陥を使用しています 。 質問そのものは、ランダムな文字列が必要な理由を明らかにすることはめったにありませんが、長さがランダムな文字列を必要とすることはめったにありません。たとえば、何らかの識別子を識別子として使用するなど、

厳密に一意の文字列を取得するは、確定的(ランダムではない)とストア/比較(不利)があります。 私たちは何をしますか? 私たちは幽霊をあきらめます。 代わりに、 確率的な一意性を持って行きます。 つまり、私たちの弦は独特のものではないという(しかし小さな)リスクがあることを承知しています。 これは、 衝突確率entropy理解が役立つところです。

だから私は、繰り返しのリスクが少ないいくつかの文字列が必要であるという不変の必要性を言い換えることにします。 具体的な例として、500万IDの可能性を生成したいとします。 新しい文字列を保存して比較したくないので、それらをランダムにしたいので、繰り返しのリスクを受け入れます。 例として、1兆ドル未満のリスクが繰り返される可能性があるとします。 文字列の長さはどれくらいですか? さて、その質問は、使用される文字に依存するので不明です。 しかし、もっと重要なことに、それは間違っています。あなたが必要とするのは、長さではなく、文字列のエントロピーの仕様です。エントロピーは、いくつかの文字列の繰り返しの確率に直接関連している可能性があります。文字列の長さはできません。

EntropyStringようなEntropyStringが役に立ちます。使用500万文字列内の繰り返しの兆チャンスで1未満を持つランダムなIDを生成するには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文字の文字セットを使用します。その他の定義済みの文字セットがあり、独自の文字も指定できます。例えば、上記と同じエントロピーで16進文字を使用して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"

使用する文字セットの文字数の合計が異なるため、文字列の長さの違いに注意してください。特定の数の潜在的な文字列の繰り返しのリスクは同じです。文字列の長さは異なります。何よりも、リピートの危険性と潜在的な文字列数は明白です。文字列の長さを推測することはもうありません。


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

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

  • 30は任意の数で、あなたは任意のトークンの長さを選ぶことができます
  • 36numeric.toString()渡すことができる最大基数です。これはすべての数字とazの小文字を意味します
  • 3は、ランダムな文字列から3番目の数字を選択するために使用されます。 "0.mfbiohx64i"0.後に任意のインデックスを取ることができます0.

あなたの好きなようにフォーマットされていないものの、一度に1つのライナーに興味がある人は、メモリを一度に割り当てることができます(ただし、小さな文字列の場合は本当に問題ありません)。

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

5あなたが望む文字列の長さで置き換えることができます。 この記事の @AriyaHidayatのおかげで、Array関数Array(5)作成された疎配列ではmap関数の解法が機能しません。


ここでダブルタップの優れた答えが改善されました 。 オリジナルには2つの欠点があります。

まず、他の人が触れたように、短い文字列を生成する可能性は低く、空の文字列(乱数が0の場合)もアプリケーションを壊す可能性があります。 ここに解決策があります:

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

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. 0のパッド(最初の問題を解決)。
  4. 先頭の「0」をスライスします。 プレフィックスと余分なパディングゼロ。
  5. 少なくともN個の文字を含むように文字列を十分に繰り返します(空の文字列と短い文字列を区切り文字として結合します)。
  6. 文字列から正確にN文字をスライスします。

さらなる考え方:

  • この解決策では大文字は使用されませんが、ほとんどの場合(意図しない)問題ではありません。
  • 元の回答のN = 16での最大文字列長はChromeで測定されます。 Firefoxでは、N = 11です。しかし、説明したように、2番目の解決策は、任意の文字列の長さをサポートすることであり、ランダム性を追加することではなく、大きな違いはありません。
  • すべての返された文字列は、少なくともMath.random()によって返された結果が均等に分布する限り、等しい確率で返されます(これは暗号強度のランダム性ではありません)。
  • サイズNの可能な文字列のすべてが返されるわけではありません。 2番目の解決策では、これは明白です(小さい文字列が単純に複製されるため)。元の回答では、これは真です。これは、基数36への変換では、最後の数ビットは元のランダムビットの一部ではない可能性があるからです。 具体的には、Math.random()。toString(36)の結果を見ると、最後の文字が均等に分布していないことがわかります。 繰り返しますが、ほとんどの場合、問題はありませんが、短い文字列(N = 1など)には影響しないように、ランダムな文字列の終わりではなく、最初から最後の文字列をスライスします。

更新:

ここに私が思いついた機能的なスタイルの1つのライナーがあります。 それらは上記の解決法とは異なります:

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

だから、あなたのアルファベットは

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

編集:

私はqubyteようqubyte 、 Martijn de Millianoは後者のような解決策を思いついた。 彼らは一見して短く見えないので、誰かが本当にワンライナーを望む場合には、私はそれをここに残します:-)

また、いくつかのバイトを減らすために、すべてのソリューションで 'new Array'を 'Array'に置き換えました。


ここに私が作成した方法があります。
大文字と小文字の両方を含む文字列が作成されます。
また、英数字の文字列を作成する関数も追加しました。

作業例:
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)));
}

このコンパクトな小さなトリックはいかがですか?

var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var stringLength = 5;

function pickRandom() {
    return possible[Math.floor(Math.random() * possible.length)];
}

var randomString = Array.apply(null, Array(stringLength)).map(pickRandom).join('');

空の配列をトリックして未定義配列にするにはArray.applyが必要です。

ES2015をコーディングする場合は、配列を作成するのが少し簡単です。

var randomString = Array.from({ length: stringLength }, pickRandom).join('');

これは確かに動作します

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

ランダムな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));


最も簡単な方法は次のとおりです。

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

これは、現在の時間に基づいて5文字のランダムな文字列を生成します。 出力例は4mtxjまたは4mv90または4mwp1

この問題は、同じ秒で2回呼び出すと、同じ文字列を生成することになります。

より安全な方法は次のとおりです。

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

これは4文字または5文字のランダムな文字列を生成しますが、常に異なっています。 出力例は30jzmまたは1r591または4su1a

両方の方法で、最初の部分は乱数を生成します。 .toString(36)部分は、その番号をbase36(英数字)表現にキャストします。


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

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


私は誰もがすでにそれを持っていることを知っているが、私は可能な限り最も軽量な方法で(コードではなく、CPUではなく)この1つに行くように感じた:

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の構文がどれほど素晴らしいかが本当にわかると思います。


要件[a-zA-Z0-9]および長さ= 5を満たすには

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

小文字、大文字、数字が表示されます。


高速で改良されたアルゴリズム。 ユニフォームを保証するものではありません(コメントを参照)。

function getRandomId(length) {
    if (!length) {
        return '';
    }

    const possible =
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let result = '';
    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);
        }
    }

    for (let i = 0; i < length; i++) {
        result += possible.charAt(array[i] % 62);
    }

    return result;
}

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


GertasとDragonが提起した問題に答えることで、Doubletapのエレガントな例を拡張しました。それらの稀なヌル状況をテストするためにwhileループを追加し、文字を5つに制限するだけです。

function rndStr() {
    x=Math.random().toString(36).substring(7).substr(0,5);
    while (x.length!=5){
        x=Math.random().toString(36).substring(7).substr(0,5);
    }
    return x;
}

結果をあなたに警告するjsfiddleがあります:http://jsfiddle.net/pLJJ7/ ://jsfiddle.net/pLJJ7/http://jsfiddle.net/pLJJ7/





random