如何在JavaScript中将十六进制字符串转换为Uint8Array,再将其转回?

46

我想将类似于bada55的十六进制字符串转换为Uint8Array,并且可以反向转换回去。

4个回答

58
Vanilla JS

const fromHexString = (hexString) =>
  Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));

const toHexString = (bytes) =>
  bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');

console.log(toHexString(Uint8Array.from([0, 1, 2, 42, 100, 101, 102, 255])));
console.log(fromHexString('0001022a646566ff'));

注意:该方法信任其输入。如果提供的输入长度为0,则会引发错误。如果十六进制编码缓冲区的长度不能被2整除,则最后一个字节将被解析为如果以0开头(例如 aaa 被解释为 aa0a)。

如果十六进制字符串可能存在格式问题或为空(例如用户输入),请在调用此方法之前检查其长度并处理错误,例如:

const isHex = (maybeHex) =>
  maybeHex.length !== 0 && maybeHex.length % 2 === 0 && !/[^a-fA-F0-9]/u.test(maybeHex);

const missingLetter = 'abc';

if (!isHex(missingLetter)) {
  console.log(`The string "${missingLetter}" is not valid hex.`)
} else {
  fromHexString(missingLetter);
}

来源: Libauth库 (hexToBin方法)


这个答案似乎存在一个问题,我遇到了...即 - UchihaItachi
1
抛出错误的条件是错误的,应该反过来写成 if(missingLetter.length % 2 !== 0) { - Andrew Koster
如果提供的十六进制字符串长度为零,则在fromHexString()中会出现故障; 在这种情况下,match()返回null而不是零长度数组,因此对map()的调用失败。 - Michael Kay
@MichaelKay - 谢谢,我添加了一个关于长度为0的输入的注释。 - Jason Dreyzehner
漂亮的 fromHexString 函数 :) - Xunnamius

36

Node.js

对于在 Node 上运行的 JavaScript,您可以这样做:

const hexString = 'bada55';

const hex = Uint8Array.from(Buffer.from(hexString, 'hex'));

const backToHexString = Buffer.from(hex).toString('hex');

(来源:此答案由@Teneff提供并获得共享许可)


4

以下是使用本地JavaScript的解决方案:

var string = 'bada55';
var bytes = new Uint8Array(Math.ceil(string.length / 2));
for (var i = 0; i < bytes.length; i++) bytes[i] = parseInt(string.substr(i * 2, 2), 16);
console.log(bytes);

var convertedBack = '';
for (var i = 0; i < bytes.length; i++) {
  if (bytes[i] < 16) convertedBack += '0';
  convertedBack += bytes[i].toString(16);
}
console.log(convertedBack);

4

浏览器(准确模拟NodeJS行为)

我需要在浏览器环境下模拟NodeJS Buffer.from(x, 'hex') 的行为,这就是我想出来的方法。

通过一些基准测试,它的速度相当快。

const HEX_STRINGS = "0123456789abcdef";
const MAP_HEX = {
  0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6,
  7: 7, 8: 8, 9: 9, a: 10, b: 11, c: 12, d: 13,
  e: 14, f: 15, A: 10, B: 11, C: 12, D: 13,
  E: 14, F: 15
};

// Fast Uint8Array to hex
function toHex(bytes) {
  return Array.from(bytes || [])
    .map((b) => HEX_STRINGS[b >> 4] + HEX_STRINGS[b & 15])
    .join("");
}

// Mimics Buffer.from(x, 'hex') logic
// Stops on first non-hex string and returns
// https://github.com/nodejs/node/blob/v14.18.1/src/string_bytes.cc#L246-L261
function fromHex(hexString) {
  const bytes = new Uint8Array(Math.floor((hexString || "").length / 2));
  let i;
  for (i = 0; i < bytes.length; i++) {
    const a = MAP_HEX[hexString[i * 2]];
    const b = MAP_HEX[hexString[i * 2 + 1]];
    if (a === undefined || b === undefined) {
      break;
    }
    bytes[i] = (a << 4) | b;
  }
  return i === bytes.length ? bytes : bytes.slice(0, i);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接