Как создать короткий UID, как "aX4j9Z" (в JS) - PullRequest
53 голосов
/ 06 июня 2011

Для моего веб-приложения (в JavaScript) я хочу создать короткие направляющие (для разных объектов - которые на самом деле являются разными типами - строки и массивы строк)

Я хочу что-то вроде "aX4j9Z" для моих uids (guids).

Таким образом, эти идентификаторы должны быть достаточно легкими для веб-передачи и обработки строк js и достаточно уникальными для небольшой структуры (не более 10 тыс. Элементов). Говоря «совершенно уникальный», я имею в виду, что после генерации uid я мог проверить, существует ли этот uid в структуре, и восстановить его, если он есть.

Ответы [ 7 ]

102 голосов
/ 06 июня 2011

См. @ ответ Мохамеда для предварительно упакованного решения (пакет shortid ). Предпочитайте это вместо любых других решений на этой странице, если у вас нет особых требований.


Буквенно-цифровая последовательность из 6 символов достаточно хороша, чтобы случайным образом индексировать коллекцию в 10 000 (36 6 = 2,2 миллиарда и 36 3 = 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, сгенерированные случайным образом, будут конфликтовать после генерации чисел ~ & radic; N (парадокс дня рождения), поэтому для безопасной генерации без проверки требуется 6 цифр (старая версия генерирует только 4 цифры, которые будут иметь коллизию после 1300 ID, если вы не проверю).

Если вы выполняете проверку столкновений, количество цифр можно уменьшить на 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_item1, user134_item2,…), если вам нужна уникальность, а не непредсказуемость. Вы можете «хэшировать» последовательно сгенерированную строку, чтобы восстановить непредсказуемость.

UID, сгенерированные с использованием Math.random, небезопасны (и вы все равно не должны доверять клиенту). не полагайтесь на его уникальность или непредсказуемость в критически важных задачах.

13 голосов
/ 17 декабря 2016

Для этого существует также потрясающий пакет npm: shorttid

Удивительно короткий непоследовательный, не зависящий от URL генератор уникальных идентификаторов.

ShortId создает удивительно короткие непоследовательные уникальные идентификаторы, дружественные по URL.Идеально подходит для сокращения URL-адресов, MongoDB и Redis-идентификаторов и любых других пользователей, которые могут видеть идентификаторы.

  • По умолчанию 7-14 удобных для URL символов: AZ, az, 0-9, _-
  • Непоследовательные, поэтому они непредсказуемы.
  • Поддерживает кластер (автоматически), пользовательские начальные числа, пользовательский алфавит.
  • Может генерировать любое количество идентификаторов без дубликатов, даже миллионы в день.
  • Идеально подходит для игр, особенно если вы беспокоитесь о мошенничестве, поэтому вам не нужен легко угадываемый идентификатор.
  • Приложения могут быть перезапущены любое количество раз без какой-либо возможности повторения идентификатора.
  • Популярная замена для Mongo ID / Mongoose ID.
  • Работает в Node, io.js и веб-браузерах.
  • Включает тесты Mocha.

Использование

var shortid = require('shortid');
console.log(shortid.generate()); //PPBqWA9
5 голосов
/ 06 июня 2011

Следующее генерирует 62 ^ 3 (238,328) уникальных значений из 3 символов, при условии, что чувствительность к регистру уникальна, а цифры разрешены во всех позициях.Если требуется нечувствительность к регистру, удалите символы верхнего или нижнего регистра из строки символов, и это сгенерирует 35 ^ 3 (42 875) уникальных значений.

Может быть легко адаптировано так, чтобы первый символ всегда был буквой, или всебуквы.

Нет, но он может быть оптимизирован, а также может отказаться от возврата идентификатора при достижении лимита.

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;
  }
}());
2 голосов
/ 16 октября 2013

Это создаст последовательность уникальных значений.Это улучшает ответ 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());
}

Эта сущность содержит вышеуказанную реализациюрекурсивная версия.

1 голос
/ 19 февраля 2012

Вы можете сократить GUID до 20 печатных символов ASCII, не теряя информацию или уникальность GUID.

Джефф Этвуд писал об этом много лет назад:
Оснащение нашей ASCII Armor

1 голос
/ 06 июня 2011
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;
}
0 голосов
/ 06 июня 2011

просто случайным образом генерирует несколько строк:

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 = {};
...