【发布时间】:2019-10-10 14:54:40
【问题描述】:
如何生成只包含给定长度的十六进制字符(0123456789abcdef)的随机字符串?
【问题讨论】:
-
究竟什么是“十六进制字符”,即
aAbBfF是否有效?另外,“正常”随机还是加密强随机? -
更新问题。正常随机就够了……
标签: javascript lodash
如何生成只包含给定长度的十六进制字符(0123456789abcdef)的随机字符串?
【问题讨论】:
aAbBfF 是否有效?另外,“正常”随机还是加密强随机?
标签: javascript lodash
使用扩展运算符和.map()的简短替代方法
const genRanHex = size => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
console.log(genRanHex(6));
console.log(genRanHex(12));
console.log(genRanHex(3));
传入一个数字 (size) 作为返回字符串的长度。
定义一个空数组 (result) 和一个范围在 [0-9] 和 [a-f] (hexRef) 的字符串数组。
在 for 循环的每次迭代中,生成一个 0 到 15 的随机数,并将其用作来自步骤 2 的字符串数组 (hexRef) 的值的索引 -- 然后是 push() 的值到第 2 步中的空数组 (result)。
将数组 (result) 作为 join('')ed 字符串返回。
const getRanHex = size => {
let result = [];
let hexRef = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
for (let n = 0; n < size; n++) {
result.push(hexRef[Math.floor(Math.random() * 16)]);
}
return result.join('');
}
console.log(getRanHex(6));
console.log(getRanHex(12));
console.log(getRanHex(3));
【讨论】:
您可以使用crypto 模块中的randomBytes 来生成给定大小的加密强伪随机数据。您可以轻松地将其转换为十六进制。
import crypto from "crypto";
const randomString = crypto.randomBytes(8).toString("hex");
console.log(randomString) // ee48d32e6c724c4d
上面的代码sn-p生成一个随机的8字节十六进制数,你可以随意操作长度。
【讨论】:
有几种方法。一种方法是从预定义的字符串中提取:
function genHexString(len) {
const hex = '0123456789ABCDEF';
let output = '';
for (let i = 0; i < len; ++i) {
output += hex.charAt(Math.floor(Math.random() * hex.length));
}
return output;
}
另一种方法是附加一个0到15之间的随机数,用toString转换为十六进制:
function genHexString(len) {
let output = '';
for (let i = 0; i < len; ++i) {
output += (Math.floor(Math.random() * 16)).toString(16);
}
return output;
}
【讨论】:
如果你可以使用 lodash 库,这里是代码 sn-p 来生成一个 16 字符的字符串:
let randomString = _.times(16, () => (Math.random()*0xF<<0).toString(16)).join('');
【讨论】:
这是一个避免一次构建一个数字的版本;它可能只适合短篇。
function genHexString(len) {
const str = Math.floor(Math.random() * Math.pow(16, len)).toString(16);
return "0".repeat(len - str.length) + str;
}
【讨论】:
这适用于最长 13 的长度:
randomHex = length => (
'0'.repeat(length)
+ Math.floor((Math.random() * 16 ** length))
.toString(16)
).slice(-length);
console.log(randomHex(4));
console.log(randomHex(6));
console.log(randomHex(13));
console.log(randomHex(20));
【讨论】:
这会安全地生成一个 32 字节的随机字符串并将其编码为十六进制(64 个字符)。
Array.from(crypto.getRandomValues(new Uint8Array(32)))
.map(b => b.toString(16).padStart(2, '0')).join('');
长版:
function generateRandomHexString(numBytes) {
const bytes = crypto.getRandomValues(new Uint8Array(numBytes));
const array = Array.from(bytes);
const hexPairs = array.map(b => b.toString(16).padStart(2, '0'));
return hexPairs.join('')
}
【讨论】:
一个 Math.random() 调用 (A) 最多可以快速获取 7 个字符:
const halfBytesIn35 = 7 // = 3.5 bytes
const byte35 = Math.pow(16, halfBytesIn35)
const bytes35 = () => ((Math.random() * byte35) | 0).toString(16).padStart(halfBytesIn35,'0')
console.log('A: ' + bytes35())
const bytes65 = len => Math.floor(Math.random() * Math.pow(16, len*2)).toString(16).padStart(len,'0')
console.log('B: ' + bytes65(6))
function moreBytes (len) {
len *= 2; // alternative: len <<= 1 if you do not use half bytes. This might allow optimizations based on len always being an Integer then.
let builder = "";
while (len > 0) {
builder += bytes35()
len -= 7
}
return builder.slice(0,len)
}
console.log('C: ' + moreBytes(16))
如果您打算高频使用,请存储 Math.pow 常量。
第 8 个字母溢出到二进制楼层的符号位中。
您可以使用 Math.floor 代替 (B) 一次调用最多 13 个字符,甚至可以循环生成任意长度 (C)。
请注意,这可用于定义过早优化。如果您的瓶颈确实是随机数的创建,请考虑使用 LUT。如果您正在为嵌入式开发,这很常见。 (在这种情况下,不知何故被 javascript 卡住了,但没有时间生成随机数)
【讨论】: