web-dev-qa-db-fra.com

Comment générer un uuid court comme "aX4j9Z" (en JS)

Pour mon application Web (en JavaScript), je veux générer des guides courts (pour différents objets - qui sont en fait des types différents - des chaînes et des tableaux de chaînes)

Je veux quelque chose comme "aX4j9Z" pour mes uids (guids).

Donc, ces uids devraient être assez légers pour le transfert Web et le traitement des chaînes js et assez uniques pour pas une structure énorme (pas plus de 10k éléments). En disant "tout à fait unique", je veux dire qu'après la génération de l'uid, je pourrais vérifier si cet uid existe déjà dans la structure et le régénérer si c'est le cas.

55
WHITECOLOR

Voir @ la réponse de Mohamed pour une solution pré-packagée (le shortid package ). Préférez cela au lieu de toute autre solution sur cette page si vous n'avez pas d'exigences particulières.


Une séquence alphanumérique à 6 caractères est assez jolie pour indexer aléatoirement une collection 10k (366 = 2,2 milliards et 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;
}

Les UID générés aléatoirement auront une collision après avoir généré des nombres ~ √N (paradoxe d'anniversaire), donc 6 chiffres sont nécessaires pour une génération sûre sans vérification (l'ancienne version ne génère que 4 chiffres qui auraient une collision après 1300 ID si vous ne vérifiez pas) .

Si vous effectuez une vérification des collisions, le nombre de chiffres peut être réduit de 3 ou 4, mais notez que les performances diminuent de façon linéaire lorsque vous générez de plus en plus d'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;
        }
    }
}

Pensez à utiliser un générateur séquentiel (par exemple user134_item1, user134_item2,…) Si vous avez besoin d'unicité et non d'imprévisibilité. Vous pouvez "hacher" la chaîne générée séquentiellement pour récupérer l'imprévisibilité.

UID générés à l'aide de Math.random n'est pas sécurisé (et vous ne devriez pas faire confiance au client de toute façon). Ne pas compter sur son caractère unique ou imprévisible dans les tâches critiques de la mission.

104
kennytm

Il y a aussi un super paquet npm pour cela: shortid

Générateur d'ID unique non séquentiel convivial et incroyablement court.

ShortId crée des identifiants uniques incroyablement courts non séquentiels adaptés aux URL. Parfait pour les raccourcisseurs d'URL, les identifiants MongoDB et Redis et tout autre identifiant que les utilisateurs pourraient voir.

  • Par défaut, 7 à 14 caractères compatibles avec les URL: A-Z, a-z, 0-9, _-
  • Non séquentiel, ils ne sont donc pas prévisibles.
  • Prend en charge le cluster (automatiquement), les graines personnalisées, l'alphabet personnalisé.
  • Peut générer n'importe quel nombre d'identifiants sans doublons, même des millions par jour.
  • Parfait pour les jeux, surtout si vous êtes préoccupé par la triche, vous ne voulez donc pas un identifiant facilement devinable.
  • Les applications peuvent être redémarrées un certain nombre de fois sans aucune possibilité de répéter un identifiant.
  • Remplacement populaire pour Mongo ID/Mongoose ID.
  • Fonctionne dans Node, io.js et les navigateurs Web.
  • Comprend les tests Mocha.

Usage

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

Ce qui suit génère 62 ^ 3 (238 328) valeurs uniques de 3 caractères à condition que la casse soit unique et que les chiffres soient autorisés dans toutes les positions. Si une insensibilité à la casse est requise, supprimez les majuscules ou les minuscules de la chaîne de caractères et cela générera 35 ^ 3 (42 875) valeurs uniques.

Peut être facilement adapté pour que le premier caractère soit toujours une lettre, ou toutes les lettres.

Aucun dobut, il peut être optimisé, et pourrait également refuser de retourner un identifiant lorsque la limite est atteinte.

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

Cela va générer une séquence de valeurs uniques. Il améliore la réponse de RobG en augmentant la longueur de la chaîne lorsque toutes les valeurs ont été épuisées.

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

Usage:

var g = new IdGenerator(),
    i;

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

This Gist contient l'implémentation ci-dessus et une version récursive.

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

Vous pouvez raccourcir un GUID à 20 caractères imprimables ASCII sans perdre d'informations ni l'unicité du GUID.

Jeff Atwood a blogué à ce sujet il y a quelques années:
Équiper notre ASCII armure

1
Christian Specht

générer simplement au hasard des chaînes:

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