字节数组到Uint64作为字符串

Vis*_*ioN 8 javascript string int64 uint64 ecmascript-6

让我们考虑以下情况.

Go例程创建一个字节数组,其中包含8字节Big Endian 的Uint64编号.5577006791947779410[77, 101, 130, 33, 7, 252, 253, 82]

在JavaScript代码中,我收到这些字节为Uint8Array.我们知道JavaScript当前不支持Uint64作为安全数字类型,并且不能对大于32位的整数执行按位运算,所以类似的东西buf[0] << 56永远不会起作用.

那么将这些字节直接解码为数字字符串的过程是什么"5577006791947779410"

PS我知道在JavaScript中有很多 用于处理大整数 ,但通常它们很大并且提供了大量的数学运算,这里我不需要.我正在寻找一个简单的现代直接解决方案,只需将BE打包的Uint64Int64字节解码为数字字符串.你有什么想法吗?

Ste*_*han 8

编辑:对于转换(U)int64我现在肯定会推荐@ LS_DEV的解决方案.我只有在拥有未知或更大的字节数时才使用我的解决方案.

我从/sf/answers/1516784111/开始并修改它:

function Int64ToString(bytes, isSigned) {
  const isNegative = isSigned && bytes.length > 0 && bytes[0] >= 0x80;
  const digits = [];
  bytes.forEach((byte, j) => {
    if(isNegative)
      byte = 0x100 - (j == bytes.length - 1 ? 0 : 1) - byte;
    for(let i = 0; byte > 0 || i < digits.length; i++) {
      byte += (digits[i] || 0) * 0x100;
      digits[i] = byte % 10;
      byte = (byte - digits[i]) / 10;
    }
  });
  return (isNegative ? '-' : '') + digits.reverse().join('');
}

const tests = [
  {
    inp: [77, 101, 130, 33, 7, 252, 253, 82],
    signed: false,
    expectation: '5577006791947779410'
  },
  {
    inp: [255, 255, 255, 255, 255, 255, 255, 255],
    signed: true,
    expectation: '-1'
  },
];

tests.forEach(test => {
  const result = Int64ToString(test.inp, test.signed);
  console.log(`${result} ${result !== test.expectation ? '!' : ''}=== ${test.expectation}`);
});
Run Code Online (Sandbox Code Playgroud)

首先,通过检查最顶部位是否设置(bytes[0] > 128)来计算符号.对于负数,必须将位取消(255 - byte),并且必须将1添加到数字(因此256而不是255最后一个字节).

foreach循环的基本思想是每个字节分成其十进制数字(byte % 10和计算开销(byte - digits[i]) / 10RESP.Math.floor(byte / 10)为下一个数位).对于下一个字节,必须添加最后字节数字(byte += digits[i] * 256resp.digits[i] << 8)的移位结果.

该代码针对简洁性,简单性和灵活性进行了优化.如果您正在处理字符串而不是字节或数字,并且不想使用任何库,那么转换性能似乎并不重要.否则,该函数可以针对性能进行优化:最多可以同时处理四个字节,一个只需要替换0x1000x80,另外(在(U)Int64的情况下只剩下两个字节组)forEach可以展开循环.对十进制数字进行分组可能不会提高性能,因为生成的字符串必须用零填充,因此需要在最终结果中删除前导零.