簡體   English   中英

javascript 中的字節數組到十六進制字符串的轉換

[英]Byte array to Hex string conversion in javascript

我有一個[4,-101,122,-41,-30,23,-28,3,..]形式的字節數組,我想將其轉換為6d69f597b217fa333246c2c8的形式,我在 function 下面使用

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

您在十六進制轉換中缺少填充。 你會想要使用

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

以便每個字節轉換為恰好兩個十六進制數字。 您的預期輸出將是04812d7e3a9829e5d51bdd64ceb35df060699bc1309731bd6e6f1a5443a7f9ce0af4382fcfd6f5f8a08bb2619709c2d49fb771601770f2c267985af2754e1f8cf9

如果輸入是Uint8Array之類的類型,則使用map()將不起作用: map()的結果也是Uint8Array ,它不能保存字符串轉換的結果。

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

使用 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)),
    '');
}

(也沒有“& 0xFF”,因為在我看來,如果傳入的數組包含大於 255 的值,輸出應該是混亂的,這樣用戶可以更容易地看到他們的輸入是錯誤的。)

由於這是“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('');
}

OP 忘記為只能用 4 位顯示的數字添加前導0

所有以前的解決方案都有效,但它們都需要創建許多字符串以及對創建的字符串進行連接和切片。 我開始認為既然有類型化數組,就必須有更好的方法來解決它。 我最初使用 node 執行此操作,然后注釋掉使用 Buffer 的行並將它們更改為 TypedArrays,以便它也可以在瀏覽器中工作。

它的代碼更多,但速度明顯更快,至少在我放在一起的快速 jsperf(不再工作)中。 接受答案中的字符串操作版本執行 37000 ops/sec,而下面的代碼管理 317000 ops/sec。 創建字符串對象有很多隱藏的開銷。

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

您需要用適當數量的前導零填充十六進制轉換。

為了保持代碼清潔,可以使用現有的庫,例如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"

在將字節數組轉換為十六進制數組時,我們必須考慮它們如何成為有符號數。 如果是這樣,我們必須先將它們轉換為十進制數。 有符號數到十進制轉換 然后,我們可以使用.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'); 
});

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

恕我直言,使用 Typescript 的更簡單的解決方案:

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

JS 版本:

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

如果在 Nodejs 上運行

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM