У меня есть байтовый массив в форме [4,-101,122,-41,-30,23,-28,3,..], который я хочу преобразовать в форму 6d69f597b217fa333246c2c8 Я использую ниже функцию

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

Что дает мне строку той же формы, но я подозреваю, что это неэффективное преобразование, потому что шестнадцатеричная строка немного короче, чем ожидалось. Я думаю, что перевод должен получить "0a10a6dc". Пожалуйста, скажите мне, если я ошибаюсь или это правильное преобразование, но, возможно, я не использую правильный байтовый массив

Байтовый массив 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

Соответствующее преобразование 4812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ceaf4382fcfd6f5f8a08bb261979c2d49fb771601770f2c267985af2754e1f8cf9

27
Actung 16 Дек 2015 в 13:49

7 ответов

Лучший ответ

Вам не хватает заполнения в шестнадцатеричном преобразовании. Вы хотите использовать

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

Так что каждый байт преобразуется ровно в две шестнадцатеричные цифры. Ваш ожидаемый результат будет 04812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ce0af4382fcfd6f5f8a08bb2619709c2d49fb771601770f2c267985af2754e1f8cf9

45
Bergi 17 Июн 2017 в 22:00

Использование map() не будет работать, если входные данные имеют тип, подобный Uint8Array: результат map() также равен Uint8Array, который не может содержать результаты преобразования строк.

function toHexString(byteArray) {
  var s = '0x';
  byteArray.forEach(function(byte) {
    s += ('0' + (byte & 0xFF).toString(16)).slice(-2);
  });
  return s;
}
7
grantpatterson 17 Июн 2017 в 19:51

Более сжатый и эффективный (см. https://jsperf.com/byte-array-to- hex-строка) альтернатива с использованием Array.reduce ():

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

(Также без «& 0xFF», потому что, по моему мнению, если массив передается, который содержит значения больше 255, выходные данные должны быть испорчены, чтобы пользователю было легче видеть, что их ввод был неправильным.)

6
AndyO 25 Июл 2018 в 13:41

Чтобы сохранить ваш код в чистоте, вы можете использовать существующие библиотеки, например, 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"
0
ns16 22 Авг 2019 в 07:13

Все предыдущие решения работают, но все они требуют создания множества строк, объединения и нарезки созданных строк. Я подумал, что должен быть лучший способ сделать это сейчас, когда есть типизированные массивы. Первоначально я сделал это с помощью узла, а затем закомментировал строки, использующие буфер, и изменил их на TypedArrays, чтобы он также работал в браузере.

Это больше кода, но он значительно быстрее, по крайней мере, в 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);
}
2
bmacnaughton 8 Апр 2019 в 18:00

Так как это первый хит Google для "js byte to hex", и мне понадобилось некоторое время, чтобы понять функцию Берги, я переписал эту функцию и добавил несколько комментариев, которые облегчили мне понимание:

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

ОП забыл добавить начальный 0 для чисел, которые могут отображаться только с 4 битами.

4
Putzi San 8 Янв 2019 в 16:09

Вам нужно дополнить шестнадцатеричное преобразование соответствующим количеством ведущих нулей.

1
void 16 Дек 2015 в 10:53