Генерация случайной строки / символов в 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)
Объяснение:
- Выберите случайное число в диапазоне [0,1), то есть от 0 (включительно) до 1 (исключая).
- Преобразуйте число в строку base-36, т. Е. Используя символы 0-9 и az.
- Подушка с нулями (решает первый вопрос).
- Отрежьте ведущий '0.' префикс и дополнительные нули дополнения.
- Повторите строку достаточное количество раз, чтобы в ней было хотя бы N символов (путем объединения пустых строк с более короткой случайной строкой, используемой в качестве разделителя).
- Вырезать ровно 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 (), что означает все цифры и строчные буквы az3
используется для выбора третьего числа из случайной строки, которая выглядит следующим образом:"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 ;
Если вы следовали приведенному выше объяснению, вы сможете создать этот буквенно-цифровой фрагмент:
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);