web-dev-qa-db-fra.com

Javascript: chaîne Unicode à hex

J'essaie de convertir une chaîne unicode en une représentation hexadécimale en javascript.

C'est ce que j'ai

function convertFromHex(hex) {
    var hex = hex.toString();//force conversion
    var str = '';
    for (var i = 0; i < hex.length; i += 2)
        str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
    return str;
}

function convertToHex(str) {
    var hex = '';
    for(var i=0;i<str.length;i++) {
        hex += ''+str.charCodeAt(i).toString(16);
    }
    return hex;
}

Mais si échoue sur les caractères unicode, comme en chinois;

Entrée: 漢字

Sortie: ªo "[W

Des idées? Cela peut-il être fait en javascript?

49
Wesley

Rappelez-vous qu'une unité de code JavaScript a une largeur de 16 bits. Par conséquent, la chaîne hexadécimale comportera 4 chiffres par unité de code.

usage:

var str = "\u6f22\u5b57"; // "\u6f22\u5b57" === "漢字"
alert(str.hexEncode().hexDecode());

Chaîne en forme hexagonale:

String.prototype.hexEncode = function(){
    var hex, i;

    var result = "";
    for (i=0; i<this.length; i++) {
        hex = this.charCodeAt(i).toString(16);
        result += ("000"+hex).slice(-4);
    }

    return result
}

De retour:

String.prototype.hexDecode = function(){
    var j;
    var hexes = this.match(/.{1,4}/g) || [];
    var back = "";
    for(j = 0; j<hexes.length; j++) {
        back += String.fromCharCode(parseInt(hexes[j], 16));
    }

    return back;
}
84
McDowell

Cela dépend de l'encodage que vous utilisez. Si vous voulez convertir une chaîne codée en utf-8 en chaîne, utilisez ceci:

function fromHex(hex,str){
  try{
    str = decodeURIComponent(hex.replace(/(..)/g,'%$1'))
  }
  catch(e){
    str = hex
    console.log('invalid hex input: ' + hex)
  }
  return str
}

Pour l’autre direction, utilisez ceci:

function toHex(str,hex){
  try{
    hex = unescape(encodeURIComponent(str))
    .split('').map(function(v){
      return v.charCodeAt(0).toString(16)
    }).join('')
  }
  catch(e){
    hex = str
    console.log('invalid text input: ' + str)
  }
  return hex
}
11
Pavel Gatnar

Voici un tweak de l'algorithme de McDowell qui ne compense pas le résultat:

  function toHex(str) {
    var result = '';
    for (var i=0; i<str.length; i++) {
      result += str.charCodeAt(i).toString(16);
    }
    return result;
  }
8
redgeoff

comment obtenez-vous "\u6f22\u5b57" à partir de 漢字 en JavaScript?

Ce sont séquences d'échappement JavaScript Unicode, par exemple \u12AB . Pour les convertir, vous pouvez parcourir toutes les unités de code de la chaîne, appeler .toString(16) et commencer à partir de là.

Cependant, il est plus efficace d'utiliser également séquences d'échappement hexadécimales, par exemple \xAA dans la sortie, dans la mesure du possible.

Notez également que ASCII) les symboles tels que A, b et - N’ont probablement pas besoin d’être échappés.

J'ai écrit une petite bibliothèque JavaScript qui fait tout cela pour vous, appelée jsesc . Il a beaucoup d'options pour contrôler la sortie.

Voici une démonstration en ligne de l'outil en action: http://mothereff.in/js-escapes#1%E6%BC%A2%E5%AD%97


Votre question a été étiquetée comme utf-8. En lisant le reste de votre question, le codage/décodage UTF-8 ne semblait pas être ce que vous vouliez ici, mais au cas où vous en auriez besoin: tilisez utf8.js ( démo en ligne ).

8
Mathias Bynens

Une solution plus à jour, pour l'encodage:

// This is the same for all of the below, and
// you probably won't need it except for debugging
// in most cases.
function bytesToHex(bytes) {
  return Array.from(
    bytes,
    byte => byte.toString(16).padStart(2, "0")
  ).join("");
}

// You almost certainly want UTF-8, which is
// now natively supported:
function stringToUTF8Bytes(string) {
  return new TextEncoder().encode(string);
}

// But you might want UTF-16 for some reason.
// .charCodeAt(index) will return the underlying
// UTF-16 code-units (not code-points!), so you
// just need to format them in whichever endian order you want.
function stringToUTF16Bytes(string, littleEndian) {
  const bytes = new Uint8Array(string.length * 2);
  // Using DataView is the only way to get a specific
  // endianness.
  const view = new DataView(bytes.buffer);
  for (let i = 0; i != string.length; i++) {
    view.setUint16(i, string.charCodeAt(i), littleEndian);
  }
  return bytes;
}

// And you might want UTF-32 in even weirder cases.
// Fortunately, iterating a string gives the code
// points, which are identical to the UTF-32 encoding,
// though you still have the endianess issue.
function stringToUTF32Bytes(string, littleEndian) {
  const codepoints = Array.from(string, c => c.codePointAt(0));
  const bytes = new Uint8Array(codepoints.length * 4);
  // Using DataView is the only way to get a specific
  // endianness.
  const view = new DataView(bytes.buffer);
  for (let i = 0; i != codepoints.length; i++) {
    view.setUint32(i, codepoints[i], littleEndian);
  }
  return bytes;
}

Exemples:

bytesToHex(stringToUTF8Bytes("hello 漢字 ????"))
// "68656c6c6f20e6bca2e5ad9720f09f918d"
bytesToHex(stringToUTF16Bytes("hello 漢字 ????", false))
// "00680065006c006c006f00206f225b570020d83ddc4d"
bytesToHex(stringToUTF16Bytes("hello 漢字 ????", true))
// "680065006c006c006f002000226f575b20003dd84ddc"
bytesToHex(stringToUTF32Bytes("hello 漢字 ????", false))
// "00000068000000650000006c0000006c0000006f0000002000006f2200005b57000000200001f44d"
bytesToHex(stringToUTF32Bytes("hello 漢字 ????", true))
// "68000000650000006c0000006c0000006f00000020000000226f0000575b0000200000004df40100"

Pour le décodage, c'est généralement beaucoup plus simple, il vous suffit de:

function hexToBytes(hex) {
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i !== bytes.length; i++) {
        bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
    }
    return bytes;
}

utilisez ensuite le paramètre d'encodage de TextDecoder:

// UTF-8 is default
new TextDecoder().decode(hexToBytes("68656c6c6f20e6bca2e5ad9720f09f918d"));
// but you can also use:
new TextDecoder("UTF-16LE").decode(hexToBytes("680065006c006c006f002000226f575b20003dd84ddc"))
new TextDecoder("UTF-16BE").decode(hexToBytes("00680065006c006c006f00206f225b570020d83ddc4d"));
// "hello 漢字 ????"

Voici la liste des noms de codage autorisés: https://www.w3.org/TR/encoding/#names-and-labels

Vous remarquerez peut-être que UTF-32 ne figure pas sur cette liste, ce qui est pénible, donc:

function bytesToStringUTF32(bytes, littleEndian) {
  const view = new DataView(bytes.buffer);
  const codepoints = new Uint32Array(view.byteLength / 4);
  for (let i = 0; i !== codepoints.length; i++) {
    codepoints[i] = view.getUint32(i * 4, littleEndian);
  }
  return String.fromCodePoint(...codepoints);
}

Ensuite:

bytesToStringUTF32(hexToBytes("00000068000000650000006c0000006c0000006f0000002000006f2200005b57000000200001f44d"), false)
bytesToStringUTF32(hexToBytes("68000000650000006c0000006c0000006f00000020000000226f0000575b0000200000004df40100"), true)
// "hello 漢字 ????"
0
Simon Buchan

Voici. :RÉ

"漢字".split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(4,"0"),"")
"6f225b57"

pour non unicode

"hi".split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(2,"0"),"")
"6869"

ASCII (utf-8) HEX binaire chaîne à chaîne

"68656c6c6f20776f726c6421".match(/.{1,2}/g).reduce((acc,char)=>acc+String.fromCharCode(parseInt(char, 16)),"")

Chaîne en chaîne HEX binaire ASCII (utf-8)

"hello world!".split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(2,"0"),"")

--- unicode ---

Chaîne en chaîne HEX binaire UNICODE (utf-16)

"hello world!".split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(4,"0"),"")

UNICODE (utf-16) HEX binaire chaîne à chaîne

"00680065006c006c006f00200077006f0072006c00640021".match(/.{1,4}/g).reduce((acc,char)=>acc+String.fromCharCode(parseInt(char, 16)),"")
0
Zibri