133 votes

Longueur de la chaîne en octets en JavaScript

Dans mon code JavaScript j'ai besoin de rédiger un message à un serveur dans ce format:

<size in bytes>CRLF
<data>CRLF

Exemple:

3
foo

Les données peuvent contenir des caractères unicode. J'ai besoin de les envoyer, comme UTF-8.

Je suis à la recherche pour la plupart de la croix-navigateur de façon à calculer la longueur de la chaîne en octets en JavaScript.

J'ai essayé de composer ma charge utile:

return unescape(encodeURIComponent(str)).length + "\n" + str + "\n"

Mais il ne me donne pas de résultats précis pour les anciens navigateurs (ou, peut-être les cordes dans ces navigateurs en UTF-16?).

Des indices?

Mise à jour:

Exemple: la longueur en octets de la chaîne ЭЭХ! Naïve? en UTF-8 est de 15 octets, mais certains navigateurs rapport de 23 octets au lieu.

100voto

Mike Samuel Points 54712

Il n'y a aucun moyen de le faire en JavaScript natif.

Si vous connaissez le codage des caractères, vous pouvez calculer vous-même cependant.

encodeURIComponent suppose l'UTF-8 comme encodage des caractères, donc si vous avez besoin que l'encodage, vous pouvez le faire,

function lengthInUtf8Bytes(str) {
  // Matches only the 10.. bytes that are non-initial characters in a multi-byte sequence.
  var m = encodeURIComponent(str).match(/%[89ABab]/g);
  return str.length + (m ? m.length : 0);
}

Cela devrait fonctionner en raison de la façon UTF-8 code multi-séquences d'octets. Le premier octet codé commence toujours avec un peu élevé de zéro pour une seule séquence d'octets, ou un octet dont le premier chiffre hexadécimal est C, D, E ou F. La deuxième et les suivantes octets sont ceux dont les deux premiers bits sont 10. Ce sont les octets supplémentaires que vous souhaitez compter en UTF-8.

La table dans le wikipedia rend plus claire

Bits        Last code point Byte 1          Byte 2          Byte 3
  7         U+007F          0xxxxxxx
 11         U+07FF          110xxxxx        10xxxxxx
 16         U+FFFF          1110xxxx        10xxxxxx        10xxxxxx
...

Si, au contraire, vous avez besoin de comprendre le codage de la page, vous pouvez utiliser cette astuce:

function lengthInPageEncoding(s) {
  var a = document.createElement('A');
  a.href = '#' + s;
  var sEncoded = a.href;
  sEncoded = sEncoded.substring(sEncoded.indexOf('#') + 1);
  var m = sEncoded.match(/%[0-9a-f]{2}/g);
  return sEncoded.length - (m ? m.length * 2 : 0);
}

77voto

lovasoa Points 189

Ici est beaucoup plus rapide de la version, ce qui ne veut pas utiliser des expressions régulières, ni encodeURIComponent:

function byteLength(str) {
  // returns the byte length of an utf8 string
  var s = str.length;
  for (var i=str.length-1; i>=0; i--) {
    var code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) s++;
    else if (code > 0x7ff && code <= 0xffff) s+=2;
    if (code >= 0xDC00 && code <= 0xDFFF) i--; //trail surrogate
  }
  return s;
}

Voici une performance de comparaison.

Il calcule la longueur en UTF8 de chaque unicode codepoints retourné par charCodeAt (basé sur wikipédia sur les descriptions de l'UTF8, et UTF16 caractères de substitution).

Il suit RFC3629 (où les caractères UTF-8 sont au plus 4 octets de long).

31voto

Lauri Oherd Points 370

Cette fonction renvoie la taille en octets de toute chaîne UTF-8 que vous lui transmettez.

 function byteCount(s) {
    return encodeURI(s).split(/%..|./).length - 1;
}
 

La source

5voto

Alexander Gladysh Points 9554

En fait, j'ai compris quel est le problème. Pour le code de la page <head> devrait avoir cette balise:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

Ou, comme suggéré dans les commentaires, si le serveur envoie une requête HTTP Content-Encoding - tête, il devrait fonctionner aussi bien.

Ensuite, les résultats de différents navigateurs sont compatibles.

Voici un exemple:

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  <title>mini string length test</title>
</head>
<body>

<script type="text/javascript">
document.write('<div style="font-size:100px">' 
    + (unescape(encodeURIComponent("ЭЭХ! Naïve?")).length) + '</div>'
  );
</script>
</body>
</html>

Note: je soupçonne que la spécification de tout (précis) de codage serait résoudre le problème d'encodage. C'est juste une coïncidence que j'ai besoin de l'UTF-8.

0voto

juytu yutyuyt Points 78

Vous pouvez essayer ceci:

 function getLengthInBytes(str) {
  var b = str.match(/[^\x00-\xff]/g);
  return (str.length + (!b ? 0: b.length)); 
}
 

Ça marche pour moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X