Генерация случайной строки / символов в JavaScript - PullRequest
1470 голосов
/ 29 августа 2009

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

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

Ответы [ 65 ]

2085 голосов
/ 10 ноября 2011

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

Примечание. Приведенный выше алгоритм имеет следующие недостатки:

  • Он будет генерировать от 0 до 6 символов из-за того, что конечные нули удаляются при строковом преобразовании с плавающей запятой.
  • Это глубоко зависит от алгоритма, используемого для строкового преобразования чисел с плавающей запятой, который ужасно сложен. (См. Статью «Как правильно печатать числа с плавающей запятой» .)
  • Math.random() может выдавать предсказуемый («случайный», но не случайный) результат в зависимости от реализации. Результирующая строка не подходит, когда вам нужно гарантировать уникальность или непредсказуемость.
  • Даже если он произвел 6 равномерно случайных, непредсказуемых символов, вы можете ожидать появления дубликата после генерации всего около 50 000 строк из-за парадокса дня рождения . (sqrt (36 ^ 6) = 46656)
2038 голосов
/ 29 августа 2009

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

function makeid(length) {
   var result           = '';
   var characters       = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
   var charactersLength = characters.length;
   for ( var i = 0; i < length; i++ ) {
      result += characters.charAt(Math.floor(Math.random() * charactersLength));
   }
   return result;
}

console.log(makeid(5));
345 голосов
/ 02 января 2015

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

Вариант 1

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

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
// i.e. 0-255 -> '00'-'ff'
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"

Для получения дополнительной информации о crypto.getRandomValues -

Метод crypto.getRandomValues() позволяет получить криптографически сильные случайные значения. Массив, заданный в качестве параметра, заполняется случайными числами (случайными в своем криптографическом значении).

Вот небольшой пример консоли -

> var arr = new Uint8Array(4) # make array of 4 bytes (values 0-255)
> arr
Uint8Array(4) [ 0, 0, 0, 0 ]

> window.crypto
Crypto { subtle: SubtleCrypto }

> window.crypto.getRandomValues()
TypeError: Crypto.getRandomValues requires at least 1 argument, but only 0 were passed

> window.crypto.getRandomValues(arr)
Uint8Array(4) [ 235, 229, 94, 228 ]

Для поддержки IE11 вы можете использовать -

(window.crypto || window.msCrypto).getRandomValues(arr)

Информацию о покрытии в браузере см. https://caniuse.com/#feat=getrandomvalues

156 голосов
/ 27 июля 2016

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

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

Math.random().toString(36).substr(2, 5);
146 голосов
/ 14 ноября 2013

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

Во-первых, как уже упоминали другие, есть небольшая вероятность создания коротких строк или даже пустой строки (если случайное число равно 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 и a-z.
  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('');

Edit:

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

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

91 голосов
/ 29 августа 2009

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

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');
77 голосов
/ 15 октября 2015

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

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

или даже

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

Обновление: Добавлен еще один подход с использованием btoa метод:

btoa(Math.random()).slice(0, 5);
btoa(+new Date).slice(-7, -2);
btoa(+new Date).substr(-7, 5);

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

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

// Using Math.random and Base 64 (btoa):
console.log(btoa(Math.random()).slice(0, 5));

// Using new Date and Base 64 (btoa):
console.log(btoa(+new Date).slice(-7, -2));
console.log(btoa(+new Date).substr(-7, 5));
67 голосов
/ 29 августа 2009

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));
47 голосов
/ 10 января 2015

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

/**
 * 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 demo


Хотя в приведенном выше примере используются дополнительные проверки для желаемого (A / N, A, N) выхода, давайте разберем его с основными (только буквенно-цифровые) для лучшего понимания:

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

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;
}
40 голосов
/ 26 ноября 2017

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

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

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