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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34309988/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:08:31  来源:igfitidea点击:

Byte array to Hex string conversion in javascript

javascriptarraysbitcoindata-conversion

提问by Actung

I have a byte array of the form [4,-101,122,-41,-30,23,-28,3,..]which I want to convert in the form 6d69f597b217fa333246c2c8I'm using below function

我有一个格式的字节数组[4,-101,122,-41,-30,23,-28,3,..],我想将其转换为6d69f597b217fa333246c2c8我在下面函数中使用的格式

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". Please tell me if I'm wrong or is this a right conversion but maybe I'm not using the right byte array

这给了我一个相同形式的字符串,但我怀疑它不是一个有效的转换,因为十六进制字符串比预期的要短一些。我认为翻译应该得到“0a10a6dc”。请告诉我我是否错了或者这是一个正确的转换,但也许我没有使用正确的字节数组

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

回答by Bergi

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

回答by grantpatterson

Using map()won't work if the input is of a type like Uint8Array: the result of map()is also Uint8Arraywhich can't hold the results of string conversion.

map()如果输入的类型为以下类型,则使用将不起作用Uint8Arraymap()is的结果也Uint8Array无法保存字符串转换的结果。

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

回答by AndyO

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 的值,输出应该会混乱,以便用户可以更容易地看到他们的输入是错误的。)

回答by Putzi San

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 0for numbers that can be displayed with only 4 bits.

OP忘记添加0只能用4位显示的数字的前导。

回答by bmacnaughton

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 jsperfI put together. The string manipulation version in the accepted answer performed 37000 ops/sec while the code below managed 317000 ops/sec. There is a lot of hidden overhead in creating string objects.

它的代码更多,但速度明显更快,至少在我放在一起的快速jsperf 中。接受的答案中的字符串操作版本执行了 37000 次操作/秒,而下面的代码管理了 317000 次操作/秒。创建字符串对象有很多隐藏的开销。

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);
}

回答by void

You need to pad the hex conversion with the appropriate number of leading zeroes.

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

回答by ns16

To keep your code clean, you can use existing libraries, e.g array-buffer-to-hex. Example:

为了保持代码干净,您可以使用现有的库,例如array-buffer-to-hex。例子:

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

const bytes = crypto.randomBytes(10)

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