简体   繁体   English

javascript 中的字节数组到十六进制字符串的转换

[英]Byte array to Hex string conversion in javascript

I have a byte array of the form [4,-101,122,-41,-30,23,-28,3,..] which I want to convert in the form 6d69f597b217fa333246c2c8 I'm using below function我有一个[4,-101,122,-41,-30,23,-28,3,..]形式的字节数组,我想将其转换为6d69f597b217fa333246c2c8的形式,我在 function 下面使用

function toHexString(bytes) {
  return bytes.map(function(byte) {
    return (byte & 0xFF).toString(16)
  }).join('')
}

which is giving me a string of the same form but I suspect that it's not an efficient conversion because the hex string is bit shorter than expected.这给了我一个相同形式的字符串,但我怀疑这不是一种有效的转换,因为十六进制字符串比预期的要短一些。 I think translating should get "0a10a6dc".我认为翻译应该得到“0a10a6dc”。 Please tell me if I'm wrong or is this a right conversion but maybe I'm not using the right byte array请告诉我我是否错了,或者这是一个正确的转换,但也许我没有使用正确的字节数组

byte array 4,-127,45,126,58,-104,41,-27,-43,27,-35,100,-50,-77,93,-16,96,105,-101,-63,48,-105,49,-67,110,111,26,84,67,-89,-7,-50,10,-12,56,47,-49,-42,-11,-8,-96,-117,-78,97,-105,9,-62,-44,-97,-73,113,96,23,112,-14,-62,103,-104,90,-14,117,78,31,-116,-7字节数组4,-127,45,126,58,-104,41,-27,-43,27,-35,100,-50,-77,93,-16,96,105,-101,-63,48,-105,49,-67,110,111,26,84,67,-89,-7,-50,10,-12,56,47,-49,-42,-11,-8,-96,-117,-78,97,-105,9,-62,-44,-97,-73,113,96,23,112,-14,-62,103,-104,90,-14,117,78,31,-116,-7

Corresponding conversion 4812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ceaf4382fcfd6f5f8a08bb261979c2d49fb771601770f2c267985af2754e1f8cf9对应转换4812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ceaf4382fcfd6f5f8a08bb261979c2d49fb771601770f2c267985af2754e1f8cf9

You are missing the padding in the hex conversion.您在十六进制转换中缺少填充。 You'll want to use你会想要使用

function toHexString(byteArray) {
  return Array.from(byteArray, function(byte) {
    return ('0' + (byte & 0xFF).toString(16)).slice(-2);
  }).join('')
}

so that each byte transforms to exactly two hex digits.以便每个字节转换为恰好两个十六进制数字。 Your expected output would be 04812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ce0af4382fcfd6f5f8a08bb2619709c2d49fb771601770f2c267985af2754e1f8cf9您的预期输出将是04812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ce0af4382fcfd6f5f8a08bb2619709c2d49fb771601770f2c267985af2754e1f8cf9

Using map() won't work if the input is of a type like Uint8Array : the result of map() is also Uint8Array which can't hold the results of string conversion.如果输入是Uint8Array之类的类型,则使用map()将不起作用: map()的结果也是Uint8Array ,它不能保存字符串转换的结果。

function toHexString(byteArray) {
  var s = '0x';
  byteArray.forEach(function(byte) {
    s += ('0' + (byte & 0xFF).toString(16)).slice(-2);
  });
  return s;
}

A more concise and performant (see https://jsperf.com/byte-array-to-hex-string ) alternative using Array.reduce():使用 Array.reduce() 的更简洁和高性能(参见https://jsperf.com/byte-array-to-hex-string )替代方案:

function toHexString(byteArray) {
  return byteArray.reduce((output, elem) => 
    (output + ('0' + elem.toString(16)).slice(-2)),
    '');
}

(Also without "& 0xFF" because in my opinion if an array is passed in that contains values larger than 255, the output should be messed up, so that the user can more easily see that their input was wrong.) (也没有“& 0xFF”,因为在我看来,如果传入的数组包含大于 255 的值,输出应该是混乱的,这样用户可以更容易地看到他们的输入是错误的。)

Since this is the first Google hit for "js byte to hex" and I needed some time to understand the function of Bergi, I rewrote the function and added some comments that made it easier for me to understand:由于这是“js byte to hex”的第一次谷歌搜索,我需要一些时间来理解 Bergi 的功能,所以我重写了该功能并添加了一些注释,使我更容易理解:

function byteToHex(byte) {
  // convert the possibly signed byte (-128 to 127) to an unsigned byte (0 to 255).
  // if you know, that you only deal with unsigned bytes (Uint8Array), you can omit this line
  const unsignedByte = byte & 0xff;

  // If the number can be represented with only 4 bits (0-15), 
  // the hexadecimal representation of this number is only one char (0-9, a-f). 
  if (unsignedByte < 16) {
    return '0' + unsignedByte.toString(16);
  } else {
    return unsignedByte.toString(16);
  }
}

// bytes is an typed array (Int8Array or Uint8Array)
function toHexString(bytes) {
  // Since the .map() method is not available for typed arrays, 
  // we will convert the typed array to an array using Array.from().
  return Array.from(bytes)
    .map(byte => byteToHex(byte))
    .join('');
}

The OP forgot to add the leading 0 for numbers that can be displayed with only 4 bits. OP 忘记为只能用 4 位显示的数字添加前导0

All of the previous solutions work but they all require the creation of many strings and concatenation and slicing of the created strings.所有以前的解决方案都有效,但它们都需要创建许多字符串以及对创建的字符串进行连接和切片。 I got thinking there has to be a better way to go about it now that there are typed arrays.我开始认为既然有类型化数组,就必须有更好的方法来解决它。 I originally did this using node and then commented out the lines that use Buffer and changed them to TypedArrays so it would work in a browser too.我最初使用 node 执行此操作,然后注释掉使用 Buffer 的行并将它们更改为 TypedArrays,以便它也可以在浏览器中工作。

It's more code but it's significantly faster, at least in the quick jsperf (no longer working) I put together.它的代码更多,但速度明显更快,至少在我放在一起的快速 jsperf(不再工作)中。 The string manipulation version in the accepted answer performed 37000 ops/sec while the code below managed 317000 ops/sec.接受答案中的字符串操作版本执行 37000 ops/sec,而下面的代码管理 317000 ops/sec。 There is a lot of hidden overhead in creating string objects.创建字符串对象有很多隐藏的开销。

function toHexString (byteArray) {
  //const chars = new Buffer(byteArray.length * 2);
  const chars = new Uint8Array(byteArray.length * 2);
  const alpha = 'a'.charCodeAt(0) - 10;
  const digit = '0'.charCodeAt(0);

  let p = 0;
  for (let i = 0; i < byteArray.length; i++) {
      let nibble = byteArray[i] >>> 4;
      chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit;
      nibble = byteArray[i] & 0xF;
      chars[p++] = nibble > 9 ? nibble + alpha : nibble + digit;    
  }

  //return chars.toString('utf8');
  return String.fromCharCode.apply(null, chars);
}

您需要用适当数量的前导零填充十六进制转换。

To keep your code clean, you can use existing libraries, eg array-buffer-to-hex . 为了保持代码清洁,可以使用现有的库,例如array-buffer-to-hex Example: 例:

const arrayBufferToHex = require('array-buffer-to-hex')
const crypto = require('crypto')

const bytes = crypto.randomBytes(10)

console.log(arrayBufferToHex(bytes)) // => "557f694f76c628fd6acb"

When converting a byte array to a hex array, we have to consider how they can be signed numbers.在将字节数组转换为十六进制数组时,我们必须考虑它们如何成为有符号数。 If so, we gotta convert them to decimal numbers first.如果是这样,我们必须先将它们转换为十进制数。 signed numbers to decimal conversion . 有符号数到十进制转换 Then, we can use the .toString(16) method to convert it to hex.然后,我们可以使用.toString(16)方法将其转换为十六进制。

const hexArr = byteArr.map((byte) => {
    if (byte < 0) {
      byte = -((byte ^ 0xff) + 1); //converting 2s complement to a decimal number
    }
    //add padding at the start to ensure it's always 2 characters long otherwise '01' will be '1'
    return byte.toString(16).padStart(2, '0'); 
});

This is cross-browser solution for ArrayBuffer:这是 ArrayBuffer 的跨浏览器解决方案:

    function buf2hex(buffer) {
        var u = new Uint8Array(buffer),
            a = new Array(u.length),
            i = u.length;
        while (i--) // map to hex
            a[i] = (u[i] < 16 ? '0' : '') + u[i].toString(16);
        u = null; // free memory
        return a.join('');
    };

IMHO, A simpler solution with Typescript:恕我直言,使用 Typescript 的更简单的解决方案:

const convertHashToHex = (value: TypedArray | number[]) : string => {
  return value.map(v => v.toString(16).padStart(2, '0')).join('');
} 

JS version: JS 版本:

const convertHashToHex = (value) => {
  return value.map(v => v.toString(16).padStart(2, '0')).join('');
} 

If running on Nodejs如果在 Nodejs 上运行

just use Buffer.toString('base64')只需使用 Buffer.toString('base64')

crypto.randomBytes(byteLength).toString('base64')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM