Генерация случайных строк/символов в JavaScript

Я хочу строку из 5 символов, состоящую из символов, выбранных случайным образом из набора [a-zA-Z0-9].

Как лучше всего это сделать с помощью JavaScript?

30 ответов


Я думаю, что это сработает для вас:

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

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

математика.random плохо для такого рода вещи

1

Если вы в состоянии сделать это сервер-сторона, просто используйте crypto модуль

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

// "bb5dc8842ca31d4603d6aa11448d1654"

результирующая строка будет в два раза длиннее случайных байтов, которые вы генерируете; каждый байт, закодированный в hex, составляет 2 символа. 20 байт будет 40 символов "сглаз".


2

Если вы должны сделать это клиент-сторона, возможно, попробуйте модуль uuid

var uuid = require("uuid");
var id = uuid.v4();

// "110ec58a-a0f2-4ac4-8393-c866d813b8d1"

3

Если вы должны сделать это клиенти вам не нужно поддерживать старые браузеры, вы можете сделать это без зависимостей

// dec2hex :: Integer -> String
function dec2hex (dec) {
  return ('0' + dec.toString(16)).substr(-2)
}

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

вот улучшение отличный ответ doubletap. Оригинал имеет два недостатка, которые рассматриваются здесь:

во-первых, как упоминали другие, он имеет небольшую вероятность создания коротких строк или даже пустой строки (если случайное число равно 0), что может нарушить ваше приложение. Вот решение:

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

во-вторых, как оригинал, так и решение выше ограничивают размер строки n до 16 символов. Следующее вернет a строка размера 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. преобразуйте число в строку base-36, т. е. используя символы 0-9 и a-z.
  3. Pad с нулями (решает первую проблему).
  4. отрежьте ведущий ' 0.' префикс и дополнительные нули заполнения.
  5. повторите строку достаточно раз, чтобы в ней было не менее N символов (путем объединения пустых строк с более короткой случайной строкой, используемой в качестве разделителя).
  6. срез ровно N символов из строки.

дальнейшие мысли:

  • это решение не использует прописные буквы, но почти во всех случаях (без каламбура) это не имеет значения.
  • максимальная длина строки при N = 16 в оригинальный ответ измеряется в Chrome. В Firefox это N = 11. Но, как уже объяснялось, второе решение заключается в поддержке любой запрошенной длины строки, а не в добавлении случайности, поэтому это не имеет большого значения.
  • все возвращаемые строки имеют равную вероятность возврата, по крайней мере, в том, что касается результатов, возвращаемых математикой.random() равномерно распределены (в любом случае это не криптографическая случайность).
  • не все возможные строки размера N может быть возвращен. Во втором решении это очевидно (так как меньшая строка просто дублируется), но и в исходном ответе это верно, так как при преобразовании в base-36 последние несколько битов могут не быть частью исходных случайных битов. В частности, если вы посмотрите на результат математики.случайный.)(toString (36), вы заметите, что последний символ распределен неравномерно. Опять же, почти во всех случаях это не имеет значения, но мы режем последнюю строку с самого начала, а не конец случайной строки, так что короткие строки (например, N=1) не затрагиваются.

обновление:

вот еще пара функциональных лайнеров, которые я придумал. Они отличаются от приведенного выше решения тем, что:

  • они используют явный произвольный алфавит (более общий и подходящий для исходного вопроса, который задавался как для прописных, так и для строчных букв).
  • все строки длины N имеют равное вероятность возврата (т. е. строки не содержат повторений).
  • они основаны на функции карты, а не на трюке toString(36), что делает их более простыми и понятными.

Итак, скажем, ваш алфавит выбора

var s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

тогда эти два эквивалентны друг другу, поэтому вы можете выбрать то, что более интуитивно понятно ты:

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

Edit:

мне кажется qubyte и Martijn de Milliano придумал решения, похожие на последние (kudos!), который я как-то пропустил. Поскольку они не выглядят так коротко с первого взгляда, я оставлю его здесь в любом случае, если кто-то действительно хочет однострочный :-)

кроме того, заменил "новый массив" на "массив" во всех решениях, чтобы сбрить еще несколько байтов.


короткий, легкий и надежный

возвращает ровно 5 случайных символов, в отличие от некоторых из лучших ответов, которые можно найти здесь.

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

что-то вроде этого должно работать

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

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

самое компактное решение, потому что slice меньше, чем substring. Вычитание из конца строки позволяет избежать символа с плавающей запятой, генерируемого random:

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

или даже

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

// Using Math.random
console.log(Math.random().toString(36).slice(-5));

// Using new Date
console.log((+new Date).toString(36).slice(-5));

Генератор Случайных Строк (Alpha-Numeric | Alpha | Numeric)

/**
 * RANDOM STRING GENERATOR
 *
 * Info:      http://stackoverflow.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) выхода, давайте разбить его на основные (только Альфа-цифры) для лучшего понимания:

  • создайте функцию, которая принимает аргумент (требуемая длина случайный результат строки)
  • создайте пустую строку, например var str = ""; для объединения случайных символов
  • внутри цикла создать rand индекс С от 0 до 61 (0..9+А..Z+a..z = 62)
  • создать условную логику to настроить/исправить rand (так как это 0..61) увеличивая его на некоторое число (см. примеры ниже), чтобы получить право CharCode номер и связанный Характер.
  • внутри цикла конкатенация к str a String.fromCharCode( incremented rand )

давайте фото таблица символов и диапазоны:

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

самый простой способ-это:

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

это генерирует случайные строки из 5 символов на основе текущего времени. Пример вывода:4mtxj или 4mv90 или 4mwp1

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

более безопасный путь:

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

это создаст случайную строку из 4 или 5 символов, всегда разных. Пример вывода похож на 30jzm или 1r591 или 4su1a

в обоих случаях первая часть генерирует случайное число. The .toString(36) часть литой количество в base36 (alphadecimal) представление о ней.


новая версия ЕС6 распространение оператор:

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

  • на 30 - произвольное число, вы можете выбрать любую длину токена, которую хотите
  • на 36 максимальное количество радикса можно передать числовой.toString (), что означает цифры и A-z строчные буквы
  • на 3 используется для выбора 3-го числа из случайной строки, которая выглядит как это: "0.mfbiohx64i", мы могли бы взять любой индекс после 0.

вот некоторые простые вкладыши. Изменить new Array(5) для установки длины.

в том числе 0-9a-z

new Array(5).join().replace(/(.|$)/g, function(){return ((Math.random()*36)|0).toString(36);})

в том числе 0-9a-zA-Z

new Array(5).join().replace(/(.|$)/g, function(){return ((Math.random()*36)|0).toString(36)[Math.random()<.5?"toString":"toUpperCase"]();});

Если вы используете Лодашь или подчеркивание, то это так просто:

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

Я знаю, что у всех уже есть это право, но я чувствовал, что хочу пойти на это самым легким способом (свет на коде, а не на процессоре):

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.


Если вы используете underscorejs можно элегантно генерировать случайную строку всего в двух строках:

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

вот метод, который я создал.
Он создаст строку, содержащую как прописные, так и строчные символы.
Кроме того, я включил функцию, которая также создаст буквенно-цифровую строку.

рабочие примеры:
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
Это делает то же самое, но больше смысла и включает в себя все письма.

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

в случае, если кто-то заинтересован в однострочном (хотя и не отформатированном как таковом для вашего удобства), который выделяет память сразу (но обратите внимание, что для небольших строк это действительно не имеет значения) вот как это сделать:

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

вы можете заменить 5 на длину строки, которую вы хотите. Благодаря @AriyaHidayat в этот пост на решение map функция не работает на разреженном массиве, созданном Array(5).


для удовлетворения требования [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;
}

function randomString (strLength, charSet) {
    var result = [];

    strLength = strLength || 5;
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    while (--strLength) {
        result.push(charSet.charAt(Math.floor(Math.random() * charSet.length)));
    }

    return result.join('');
}

это так чисто, как это будет. Это тоже быстро,http://jsperf.com/ay-random-string.


вы можете перебирать массив элементов и рекурсивно добавлять их в строковую переменную, например, если вам нужна случайная последовательность ДНК:

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

Я не нашел чистого решения для поддержки как строчных, так и прописных символов.

поддержка только в нижнем регистре:

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

основываясь на этом решении для поддержки нижнего и верхнего регистров:

Math.random().toString(36).substr(2, 5).split('').map(c => Math.random() < 0.5 ? c.toUpperCase() : c).join('');

изменить 5 на substr(2, 5) отрегулировать к длине вам.


Как насчет чего-то вроде этого: Date.now().toString(36) Не очень случайный, но короткий и довольно уникальный каждый раз, когда вы его называете.


это работает точно

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

создать строку длиной 10 символов. Длина задается параметром (по умолчанию 10).

function random_string_generator(len) {
var len = len || 10;
var str = '';
var i = 0;

for(i=0; i<len; i++) {
    switch(Math.floor(Math.random()*3+1)) {
        case 1: // digit
            str += (Math.floor(Math.random()*9)).toString();
        break;

        case 2: // small letter
            str += String.fromCharCode(Math.floor(Math.random()*26) + 97); //'a'.charCodeAt(0));
        break;

        case 3: // big letter
            str += String.fromCharCode(Math.floor(Math.random()*26) + 65); //'A'.charCodeAt(0));
        break;

        default:
        break;
    }
}
return str;
}

вот тестовый скрипт для ответа #1 (Спасибо @csharptest.net)

скрипт makeid() 1 million раз и, как вы можете видеть, 5 не является очень уникальным. запуск его с длиной char 10 довольно надежен. Я запускал его около 50 раз и еще не видел дубликат :-)

Примечание: ограничение размера стека узла превышает около 4 миллионов, поэтому вы не можете запустить этот 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');

можно использовать coderain. Это библиотека для генерации случайных кодов в соответствии с заданным шаблоном. Использовать # в качестве заполнителя для символов верхнего и нижнего регистра, а также цифр:

var cr = new CodeRain("#####");
console.log(cr.next());

есть другие заполнители, такие как A для прописных букв или 9 для цифр.

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

вот демо приложения создает список уникальных случайных кодов.

полное раскрытие: я-автор coderain.


как насчет этого компактного трюк?

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 есть, чтобы обмануть пустой массив в массив undefineds.

Если вы кодируете ES2015, то построение массива немного проще:

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

проблема с ответами на "мне нужны случайные строки" вопросы (на любом языке) практически каждое решение использует ущербную основная спецификация длина строки. Сами вопросы редко показывают, зачем нужны случайные строки, но я бы бросил вызов вам редко нужны случайные строки длины, скажем 8. То, что вам неизменно нужно, - это некоторое количество уникальные строки, например, использовать в качестве идентификаторов для некоторых цель.

есть два ведущих способа получить строго уникальные строки: детерминированно (что не является случайным) и хранить / сравнивать (что является обременительным). Что будем делать? Мы оставляем призрак. Мы идем с вероятностные уникальность. То есть мы признаем, что существует некоторый (хотя и небольшой) риск того, что наши строки не будут уникальными. Вот где понимание вероятность столкновения и энтропия полезны.

поэтому я перефразирую неизменную потребность как нуждающуюся в некотором количестве строк с небольшим риском повторения. В качестве конкретного примера предположим, что вы хотите создать потенциал в 5 миллионов идентификаторов. Вы не хотите хранить и сравнивать каждую новую строку, и вы хотите, чтобы они были случайными, поэтому вы принимаете некоторый риск повторения. В качестве примера, скажем, риск менее 1 из триллиона шансов повторения. Так какая длина шнура вам нужна? Что ж, этот вопрос недооценен, поскольку он зависит от используемых символов. Но что более важно, это заблуждение. Вам нужна спецификация энтропии строк, а не их длины. Энтропия может быть напрямую связана с вероятностью повторения в некотором количестве строк. Длина строки не может.

и это Где Библиотека, как EntropyString могу помочь. Чтобы генерировать случайные идентификаторы, которые имеют менее 1 из триллиона шансов повторения в 5 миллионах строк, используя 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 символами. Существуют другие предопределенные наборы символов, и вы также можете указать свои собственные символы. Например, создание идентификаторов с той же энтропией, что и выше, но с использованием шестнадцатеричных символов:

import {Random, Entropy, charSet16} from './entropy-string'

const random = new Random(charSet16)
const bits = Entropy.bits(5e6, 1e12)

const string = random.string(bits)

"27b33372ade513715481f"

обратите внимание на разницу в длине строки из-за разницы в общей количество используемых символов в наборе символов. Риск повторения в указанном количестве потенциальных строк одинаков. Длина строки-нет. И лучше всего, риск повторения и потенциальное количество строк является явным. Больше никаких догадок с длиной строки.


расширение элегантного примера Doubletap, отвечая на вопросы, поднятые Гертасом и Драконом. Просто добавьте цикл while для проверки этих редких нулевых обстоятельств и ограничьте символы пятью.

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/