Мне нужна строка из 5 символов, состоящая из символов, выбранных случайным образом из набора [a-zA-Z0-9]
.
Какой лучший способ сделать это с помощью JavaScript?
Мне нужна строка из 5 символов, состоящая из символов, выбранных случайным образом из набора [a-zA-Z0-9]
.
Какой лучший способ сделать это с помощью JavaScript?
Я думаю, что это будет работать для вас:
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));
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
// 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"
Возвращает ровно 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)
Пояснение:
Дальнейшие мысли:
Update:
Вот пара других функциональных стилей с одним слоем, которые я придумал. Они отличаются от решения выше тем, что:
Итак, скажем, ваш алфавит выбора
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!), который я как-то пропустил. Поскольку они не выглядят краткими, я останусь здесь все равно, если кто-то действительно хочет однострочный: -)
Кроме того, заменить "новый массив" на "Array" во всех решениях, чтобы слить еще несколько байтов.
Что-то вроде этого должно работать
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);
Обновление: добавлен еще один подход с использованием метода 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));
/**
* 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) вывода, пусть разбивает его на основные (только Alpha-Numeric) для лучшего понимания:
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 ;
Если вы следуете приведенному выше объяснению, вы сможете создать этот альфа-цифровой фрагмент:
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;
}
Более новая версия с оператором распространения es6:
[...Array(30)].map(() => Math.random().toString(36)[2]).join('')
30
- произвольное число, вы можете выбрать любую желаемую длину токена36
- это максимальное число радиуса, которое вы можете передать numeric.toString(), что означает все цифры и строчные буквы az2
используется для выбора 2-го числа из случайной строки, которая выглядит следующим образом: "0.mfbiohx64i"
, мы можем взять любой индекс после 0.
Самый простой способ:
(new Date%9e6).toString(36)
Это генерирует случайные строки из 5 символов в зависимости от текущего времени. Пример вывода: 4mtxj
или 4mv90
или 4mwp1
Проблема заключается в том, что если вы вызовете это два раза за ту же секунду, она будет генерировать ту же строку.
Более безопасный способ:
(0|Math.random()*9e6).toString(36)
Это создаст случайную строку из 4 или 5 символов, всегда отличающуюся. Пример вывода похож на 30jzm
или 1r591
или 4su1a
В обоих случаях первая часть генерирует случайное число. Часть .toString(36)
передала число в базовое36 (буквенно-цифровое) представление.
Вот несколько простых лайнеров. Измените 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 rand(length, current) {
current = current ? current : '';
return length ? rand(--length, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".charAt(Math.floor(Math.random() * 60)) + current) : current;
}
console.log(rand(5));
Если вы используете Lodash или Underscore, то это так просто:
var randomVal = _.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 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)));
}
Предполагая, что вы используете underscorejs, можно элегантно генерировать случайную строку только в двух строках:
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var random = _.sample(possible, 5).join('');
Если кто-то интересуется однострочным (хотя и не отформатированным как таковое для вашего удобства), который выделяет память сразу (но обратите внимание, что для небольших строк это действительно не имеет значения) вот как это сделать:
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 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 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.
Я не нашел чистого решения для поддержки как строчных, так и прописных букв.
Поддержка только в нижнем регистре:
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
in substr(2, 5)
чтобы настроить нужную длину.
Это верно.
<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;
}
Как насчет этого компактного маленького трюка?
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('');
Вы можете использовать coderain. Это библиотека для генерации случайных кодов в соответствии с заданным шаблоном. Используйте #
в качестве заполнителя для символов верхнего и нижнего регистра, а также цифр:
var cr = new CodeRain("#####");
console.log(cr.next());
Существуют другие заполнители, такие как A
для прописных букв или 9
для цифр.
Что может быть полезно, так это то, что вызов .next()
всегда даст вам уникальный результат, поэтому вам не придется беспокоиться о дубликатах.
Вот демонстрационное приложение, которое создает список уникальных случайных кодов.
Полное раскрытие: я автор кодераина.
Проблема с ответами на вопросы "Мне нужны случайные строки" (на любом языке) практически в каждом решении используется некорректная первичная спецификация длины строки. Сами вопросы редко показывают, почему нужны случайные строки, но я бы бросил вызов вам редко нужны случайные строки длины, скажем 8. То, что вам обязательно нужно, это некоторое количество уникальных строк, например, для использования в качестве идентификаторов для какой-то цели.
Существует два ведущих способа получить строго уникальные строки: детерминистически (что не случайно) и хранить/сравнивать (что является обременительным). Что мы делаем? Мы бросаем призрак. Вместо этого мы идем с вероятностной уникальностью. То есть мы согласны с тем, что существует (хотя и небольшой) риск того, что наши строки не будут уникальными. Здесь понимание вероятность столкновения и entropy полезны.
Итак, я буду перефразировать неизменную потребность, поскольку вам нужно некоторое количество строк с небольшим риском повторения. В качестве конкретного примера предположим, что вы хотите создать потенциал в 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"
Обратите внимание на разницу в длине строки из-за разницы в общем количестве символов в используемом наборе символов. Риск повторения в указанном числе потенциальных строк одинаковый. Длина строк не является. И, самое главное, риск повторения и потенциального количества строк является явным. Больше не догадывается длина строки.
Как насчет чего-то вроде этого: Date.now().toString(36)
Не очень случайный, но короткий и совершенно уникальный каждый раз, когда вы его называете.
Вот тест script для ответа # 1 (спасибо @csharptest.net)
script запускает makeid()
1 million
раз, и, как вы видите, 5 не является уникальным. запуск его с длиной char 10 достаточно надежный. Я запускал его примерно 50 раз и еще не видел дубликата :-)
Примечание: ограничение размера стека node превышает около 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');
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));