У меня есть байтовый массив в форме [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
7 ответов
Вам не хватает заполнения в шестнадцатеричном преобразовании. Вы хотите использовать
function toHexString(byteArray) {
return Array.from(byteArray, function(byte) {
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
}).join('')
}
Так что каждый байт преобразуется ровно в две шестнадцатеричные цифры. Ваш ожидаемый результат будет 04812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ce0af4382fcfd6f5f8a08bb2619709c2d49fb771601770f2c267985af2754e1f8cf9
Использование map()
не будет работать, если входные данные имеют тип, подобный Uint8Array
: результат map()
также равен Uint8Array
, который не может содержать результаты преобразования строк.
function toHexString(byteArray) {
var s = '0x';
byteArray.forEach(function(byte) {
s += ('0' + (byte & 0xFF).toString(16)).slice(-2);
});
return s;
}
Более сжатый и эффективный (см. 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, выходные данные должны быть испорчены, чтобы пользователю было легче видеть, что их ввод был неправильным.)
Чтобы сохранить ваш код в чистоте, вы можете использовать существующие библиотеки, например, 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"
Все предыдущие решения работают, но все они требуют создания множества строк, объединения и нарезки созданных строк. Я подумал, что должен быть лучший способ сделать это сейчас, когда есть типизированные массивы. Первоначально я сделал это с помощью узла, а затем закомментировал строки, использующие буфер, и изменил их на 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);
}
Так как это первый хит 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('');
}
- Для получения дополнительной информации о
const unsignedByte = byte & 0xff
- части проверьте Что делает AND 0xFF? а> . -
Array.from
is не доступно в каждом браузере (например, не в IE11), проверьте Как преобразовать типизированный массив JavaScript в массив JavaScript для получения дополнительной информации
ОП забыл добавить начальный 0
для чисел, которые могут отображаться только с 4 битами.
Вам нужно дополнить шестнадцатеричное преобразование соответствующим количеством ведущих нулей.
Похожие вопросы
Связанные вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript / JS) и его различных диалектах / реализациях (кроме ActionScript). Включите все соответствующие теги в свой вопрос; например, [node.js], [jquery], [json] и т. д.