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

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

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

94 ответа

Решение

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

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

Math.random это плохо для такого рода вещей

Опция 1

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

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

// "bb5dc8842ca31d4603d6aa11448d1654"

Результирующая строка будет в два раза длиннее случайных байтов, которые вы генерируете; каждый байт, закодированный в шестнадцатеричный код, состоит из 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"

Коротко, просто и надежно

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

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

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

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

(Math.random().toString(36)+'00000000000000000').slice(2, N+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. Преобразуйте число в строку base-36, т. Е. Используя символы 0-9 и az.
  3. Подушка с нулями (решает первый вопрос).
  4. Отрежьте ведущий '0.' префикс и дополнительные нули дополнения.
  5. Повторите строку достаточное количество раз, чтобы в ней было хотя бы N символов (путем объединения пустых строк с более короткой случайной строкой, используемой в качестве разделителя).
  6. Вырезать ровно N символов из строки.

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

  • Это решение не использует заглавные буквы, но почти во всех случаях (без каламбура) это не имеет значения.
  • Максимальная длина строки при N = 16 в исходном ответе измеряется в Chrome. В Firefox это N = 11. Но, как объяснено, второе решение заключается в поддержке любой запрашиваемой длины строки, а не в добавлении случайности, поэтому это не имеет большого значения.
  • Все возвращаемые строки имеют одинаковую вероятность возврата, по крайней мере, если результаты, возвращаемые Math.random(), распределены равномерно (в любом случае это не случайность с криптографической стойкостью).
  • Не все возможные строки размера N могут быть возвращены. Во втором решении это очевидно (поскольку строка меньшего размера просто дублируется), но и в исходном ответе это верно, поскольку при преобразовании в base-36 последние несколько битов могут не являться частью исходных случайных битов. В частности, если вы посмотрите на результат Math.random(). 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('');

Редактировать:

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

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

Самое компактное решение, потому что 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));

Более новая версия с оператором распространения es6:

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

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

Как то так должно работать

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

Генератор случайных строк (буквенно-цифровой | буквенно-цифровой)

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

  • Создайте функцию, которая принимает аргумент (желаемую длину случайного результата String)
  • Создайте пустую строку как var str = ""; объединить случайные символы
  • Внутри цикла создайте rand порядковый номер от 0 до 61 (0,9+A..Z+a..z = 62)
  • Создать условную логику для настройки / исправления rand (так как это 0..61) увеличивая его на некоторое число (см. примеры ниже), чтобы получить право CharCode номер и связанный с ним персонаж.
  • Внутри цикла объединить с str 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;
}

Для удовлетворения требования [a-zA-Z0-9] и длины =5 используйте

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

Будут встречаться строчные буквы, прописные буквы и цифры.

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

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

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

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

Более безопасный способ:

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

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

В обоих случаях первая часть генерирует случайное число. .toString(36) part приведёт число к его базовому (алфавитному) представлению.

Вот несколько простых лайнеров. + Изменить 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"]();});

Нет лучшего способа сделать это. Вы можете делать это как хотите, если результат соответствует вашим требованиям. Чтобы проиллюстрировать это, я создал много разных примеров, и все они должны давать одинаковый конечный результат.

Большинство других ответов на этой странице игнорируют требование к символам верхнего регистра.

Вот мое самое быстрое и удобочитаемое решение . Он в основном делает то же самое, что и принятое решение, за исключением того, что он немного быстрее.

      function readableRandomStringMaker(length) {
  for (var s=''; s.length < length; s += 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.charAt(Math.random()*62|0));
  return s;
}
console.log(readableRandomStringMaker(length));
// e3cbN

Вот компактная рекурсивная версия, которая гораздо менее читаема:

      const compactRandomStringMaker = (length) => length-- && "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62|0) + (compactRandomStringMaker(length)||"");
console.log(compactRandomStringMaker(5));
// DVudj

Более компактный один вкладыш :

      Array(5).fill().map(()=>"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62)).join("")
// 12oEZ

Вариант вышеперечисленного:

      "     ".replaceAll(" ",()=>"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62))

Самые компактные один лайнер, но неэффективны и нечитаемый - это добавляет случайные символы и удаляет недопустимые символы до тех пор , пока длина л :

      ((l,f=(p='')=>p.length<l?f(p+String.fromCharCode(Math.random()*123).replace(/[^a-z0-9]/i,'')):p)=>f())(5)

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

      [...crypto.getRandomValues(new Uint8Array(999))].map((c)=>String.fromCharCode(c).replace(/[^a-z0-9]/i,'')).join("").substr(0,5)
// 8fzPq

Или без аргумента длины это еще короче:

      ((f=(p='')=>p.length<5?f(p+String.fromCharCode(Math.random()*123).replace(/[^a-z0-9]/i,'')):p)=>f())()
// EV6c9

Затем посложнее - использовать безымянную рекурсивную стрелочную функцию :

      ((l,s=((l)=>l--&&"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62|0)+(s(l)||""))) => s(l))(5);
// qzal4

Это «волшебная» переменная, которая предоставляет случайный символ каждый раз, когда вы к ней обращаетесь:

      const c = new class { [Symbol.toPrimitive]() { return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62|0) } };
console.log(c+c+c+c+c);
// AgMnz

Более простой вариант вышеперечисленного:

      const c=()=>"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62|0);
c()+c()+c()+c()+c();
// 6Qadw

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

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.

Создать безопасный случайный буквенно-цифровой Base-62 строка:

function generateUID(length)
{
    return window.btoa(Array.from(window.crypto.getRandomValues(new Uint8Array(length * 2))).map((b) => String.fromCharCode(b)).join("")).replace(/[+/]/g, "").substring(0, length);
}

console.log(generateUID(22)); // "yFg3Upv2cE9cKOXd7hHwWp"
console.log(generateUID(5)); // "YQGzP"

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

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

Если вы используете Lodash или Underscore, то это так просто:

var randomVal = _.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 5).join('');
const c = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
const s = Array.from({length:5}, _ => c[Math.floor(Math.random()*c.length)]).join('')

Улучшенный ответ @Andrew выше:

Array.from({ length : 1 }, () => Math.random().toString(36)[2]).join('');

Преобразование случайного числа по базе 36 непоследовательно, поэтому выбор одного индекса исправляет это. Вы можете изменить длину строки на нужную длину.

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

Рабочие примеры:
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(15).fill(null).map(() => Math.random().toString(36).substr(2)).join('')
// Outputs: 0h61cbpw96y83qtnunwme5lxk1i70a6o5r5lckfcyh1dl9fffydcfxddd69ada9tu9jvqdx864xj1ul3wtfztmh2oz2vs3mv6ej0fe58ho1cftkjcuyl2lfkmxlwua83ibotxqc4guyuvrvtf60naob26t6swzpil

Предполагая, что вы используете http://underscorejs.org/, можно элегантно сгенерировать случайную строку всего за две строки:

var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var random = _.sample(possible, 5).join('');
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 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;
}

Хотя этот ответ почти похож на другие, он отличается тем, что использует:

  • для создания 5 символов (можно обобщить доn)
  • repeatс регулярным выражением/./gзаменить эти 5 символов
  • формула случайным образом выбирает символ из 62-символьной строки A-Za-z0-9

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

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

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

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

Буквенно-цифровые символы без учета регистра:

function randStr(len) {
  let s = '';
  while (s.length < len) s += Math.random().toString(36).substr(2, len - s.length);
  return s;
}

// usage
console.log(randStr(50));

Преимущество этой функции в том, что вы можете получить произвольную строку разной длины, и она обеспечивает длину строки.

Чувствительный к регистру все символы:

function randStr(len) {
  let s = '';
  while (len--) s += String.fromCodePoint(Math.floor(Math.random() * (126 - 33) + 33));
  return s;
}

// usage
console.log(randStr(50));

Пользовательские символы

function randStr(len, chars='abc123') {
  let s = '';
  while (len--) s += chars[Math.floor(Math.random() * chars.length)];
  return s;
}

// usage
console.log(randStr(50));
console.log(randStr(50, 'abc'));
console.log(randStr(50, 'aab')); // more a than b

Крипто-сильный

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

let pass = [...crypto.getRandomValues(new Uint8Array(5))]
   .map((x,i)=>(i=x/255*61|0,String.fromCharCode(i+(i>9?i>35?61:55:48)))).join``

let pass = [...crypto.getRandomValues(new Uint8Array(5))]
   .map((x,i)=>(i=x/255*61|0,String.fromCharCode(i+(i>9?i>35?61:55:48)))).join``

console.log(pass);

Другие вопросы по тегам