web-dev-qa-db-ja.com

「aX4j9Z」のような短いuidを生成する方法(JSで)

私のWebアプリケーション(JavaScript)で、短いGUID(異なるオブジェクト-実際には異なるタイプ-文字列と文字列の配列)を生成したい

Uid(guid)に「aX4j9Z」のようなものが必要です。

したがって、これらのuidは、Web転送とjs文字列処理に十分な軽量で、巨大な構造(1万個以下の要素)には非常にユニークでなければなりません。 「非常にユニーク」と言うことは、uidの生成後に、このuidが既に構造内に存在するかどうかを確認し、存在する場合は再生成できることを意味します。

55
WHITECOLOR

事前にパッケージ化されたソリューションについては、 @ Mohamed's answer を参照してください( shortid package )。特別な要件がない場合は、このページの他のソリューションの代わりにそれを使用してください。


6文字の英数字シーケンスは、10,000個のコレクションをランダムにインデックス付けするのに十分です(366 = 22億と363 = 46656)。

function generateUID() {
    // I generate the UID from two parts here 
    // to ensure the random number provide enough bits.
    var firstPart = (Math.random() * 46656) | 0;
    var secondPart = (Math.random() * 46656) | 0;
    firstPart = ("000" + firstPart.toString(36)).slice(-3);
    secondPart = ("000" + secondPart.toString(36)).slice(-3);
    return firstPart + secondPart;
}

ランダムに生成されたUIDは、〜√Nの数を生成した後に衝突します(誕生日の逆説)。したがって、チェックなしで安全に生成するには6桁が必要です(古いバージョンでは、1300 IDをチェックしないと衝突する4桁しか生成されません) 。

衝突チェックを行う場合、桁数を3または4減らすことができますが、UIDをますます生成するとパフォーマンスが直線的に低下することに注意してください。

var _generatedUIDs = {};
function generateUIDWithCollisionChecking() {
    while (true) {
        var uid = ("0000" + ((Math.random() * Math.pow(36, 4)) | 0).toString(36)).slice(-4);
        if (!_generatedUIDs.hasOwnProperty(uid)) {
            _generatedUIDs[uid] = true;
            return uid;
        }
    }
}

予測不可能性ではなく一意性が必要な場合は、シーケンシャルジェネレーター(例:user134_item1user134_item2、…)の使用を検討してください。連続して生成された文字列を「ハッシュ」して、予測不能性を回復できます。

Math.randomを使用して生成されたUIDは安全ではありません(とにかくクライアントを信頼するべきではありません)。 notは、ミッションクリティカルなタスクにおけるその一意性または予測不可能性に依存しています。

104
kennytm

このための素晴らしいnpmパッケージもあります: shortid

非常に短いノンシーケンシャルURLフレンドリーなユニークIDジェネレーター。

ShortIdは、驚くほど短い非シーケンシャルURLフレンドリーな一意のIDを作成します。 URL短縮サービス、MongoDB、Redis ID、その他のIDユーザーに最適です。

  • デフォルトでは、7-14のURLフレンドリー文字:A-Z、a-z、0-9、_-
  • ノンシーケンシャルなので、予測できません。
  • クラスター(自動)、カスタムシード、カスタムアルファベットをサポートします。
  • 重複することなく、1日あたり数百万のIDをいくつでも生成できます。
  • ゲームに最適です。特に、簡単に推測できるIDが欲しくないため、不正行為が気になる場合に最適です。
  • IDを繰り返すことなく、アプリを何度でも再起動できます。
  • Mongo ID/Mongoose IDの一般的な代替品。
  • Node、io.js、およびWebブラウザーで動作します。
  • Mochaテストが含まれています。

使用法

var shortid = require('shortid');
console.log(shortid.generate()); //PPBqWA9
13
Mohamed Ramrami

次の例では、大文字と小文字の区別が一意であり、すべての位置で数字が許可されている場合、3文字の62 ^ 3(238,328)の一意の値が生成されます。大文字と小文字を区別しない場合は、chars文字列から大文字または小文字を削除すると、35 ^ 3(42,875)個の一意の値が生成されます。

最初の文字が常に文字、またはすべての文字になるように簡単に適応できます。

最適化することはできません。また、制限に達したときにIDを返すことを拒否することもできます。

var nextId = (function() {
  var nextIndex = [0,0,0];
  var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
  var num = chars.length;

  return function() {
    var a = nextIndex[0];
    var b = nextIndex[1];
    var c = nextIndex[2];
    var id = chars[a] + chars[b] + chars[c];

    a = ++a % num;

    if (!a) {
      b = ++b % num; 

      if (!b) {
        c = ++c % num; 
      }
    }
    nextIndex = [a, b, c]; 
    return id;
  }
}());
5
RobG

これにより、一意の値のシーケンスが生成されます。すべての値が使い果たされたときに文字列の長さを増やすことにより、RobGの答えを改善します。

var IdGenerator = (function () {

    var defaultCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_-+=[]{};:?/.>,<|".split("");

    var IdGenerator = function IdGenerator(charset) {
        this._charset = (typeof charset === "undefined") ? defaultCharset : charset;
        this.reset();
    };

    IdGenerator.prototype._str = function () {
        var str = "",
            perm = this._perm,
            chars = this._charset,
            len = perm.length,
            i;
        for (i = 0; i < len; i++) {
            str += chars[perm[i]];
        }
        return str;
    };

    IdGenerator.prototype._inc = function () {
        var perm = this._perm,
            max = this._charset.length - 1,
            i;
        for (i = 0; true; i++) {
            if (i > perm.length - 1) {
                perm.Push(0);
                return;
            } else {
                perm[i]++;
                if (perm[i] > max) {
                    perm[i] = 0;
                } else {
                    return;
                }
            }
        }
    };

    IdGenerator.prototype.reset = function () {
        this._perm = [];
    };

    IdGenerator.prototype.current = function () {
        return this._str();
    };

    IdGenerator.prototype.next = function () {
        this._inc();
        return this._str();
    };

    return IdGenerator;

}).call(null);

使用法:

var g = new IdGenerator(),
    i;

for (i = 0; i < 100; i++) {
   console.log(g.next());
}

この要点 には上記の実装と再帰バージョンが含まれています。

2
Ilia Choly
var letters = 'abcdefghijklmnopqrstuvwxyz';
var numbers = '1234567890';
var charset = letters + letters.toUpperCase() + numbers;

function randomElement(array) {
    with (Math)
        return array[floor(random()*array.length)];
}

function randomString(length) {
    var R = '';
    for(var i=0; i<length; i++)
        R += randomElement(charset);
    return R;
}
1
ninjagecko

GUID= 20文字まで印刷可能ASCII文字を情報やGUIDの一意性を失うことなく短縮できます。

Jeff Atwoodはその数年前にブログを書きました:
ASCII Armor

1

ランダムにいくつかの文字列を生成するだけです:

function getUID(len){
    var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
          out = '';

    for(var i=0, clen=chars.length; i<len; i++){
       out += chars.substr(0|Math.random() * clen, 1);
    }

    // ensure that the uid is unique for this page
    return getUID.uids[out] ? getUID(len) : (getUID.uids[out] = out);
}
getUID.uids = {};
0
Mark Kahn