web-dev-qa-db-fra.com

Combien d'octets dans une chaîne JavaScript?

J'ai une chaîne javascript qui est d'environ 500K lors de l'envoi du serveur en UTF-8. Comment savoir sa taille en JavaScript?

Je sais que JavaScript utilise UCS-2, cela signifie donc 2 octets par caractère. Cependant, cela dépend-il de l'implémentation de JavaScript? Ou sur la page d'encodage ou peut-être contenu-type?

63
Paul Biggar

Les valeurs String ne dépendent pas de la mise en oeuvre, selon la spécification ECMA-262 3rd Edition , chaque caractère représente une seule unité 16 bits de texte UTF-16:

4.3.16 Valeur de chaîne

Une valeur de chaîne est un membre du type String et est un séquence finie ordonnée de zéro ou plus de valeurs entières non signées sur 16 bits.

NOTE Bien que chaque valeur habituellement représente une seule unité de 16 bits de Texte UTF-16, la langue n’est pas placer des restrictions ou des exigences sur les valeurs sauf qu'elles soient Entiers non signés 16 bits.

26
CMS

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

Les moteurs JavaScript sont libres d'utiliser UCS-2 ou UTF-16 en interne. La plupart des moteurs que je connais utilisent UTF-16, mais quel que soit leur choix, il ne s’agit que d’un détail de mise en œuvre qui n’affectera pas les caractéristiques de la langue.

Le langage ECMAScript/JavaScript lui-même, cependant, expose les caractères selon UCS-2, pas UTF-16.

La source

56
Lauri Oherd

Si vous utilisez node.js, il existe une solution plus simple utilisant buffers :

function getBinarySize(string) {
    return Buffer.byteLength(string, 'utf8');
}

Il existe une lib npm pour cela: https://www.npmjs.org/package/utf8-binary-cutter (de votre part fidèlement)

29
Offirmo

Essayez cette combinaison en utilisant unescape fonction js:

const byteAmount = unescape(encodeURIComponent(yourString)).length

Exemple de processus d'encodage complet:

const s  = "1 a ф № @ ®"; //length is 11
const s2 = encodeURIComponent(s); //length is 41
const s3 = unescape(s2); //length is 15 [1-1,a-1,ф-2,№-3,@-1,®-2]
const s4 = escape(s3); //length is 39
const s5 = decodeURIComponent(s4); //length is 11
19
Kinjeiro

UTF-8 code les caractères en utilisant 1 à 4 octets par point de code. Comme le CMS l'a indiqué dans la réponse acceptée, JavaScript stockera chaque caractère en interne sur 16 bits (2 octets).

Si vous analysez chaque caractère de la chaîne via une boucle et comptez le nombre d'octets utilisés par point de code, puis multipliez le nombre total par 2, l'utilisation de la mémoire par JavaScript en octets pour cette chaîne codée UTF-8. Peut-être quelque chose comme ça:

      getStringMemorySize = function( _string ) {
        "use strict";

        var codePoint
            , accum = 0
        ;

        for( var stringIndex = 0, endOfString = _string.length; stringIndex < endOfString; stringIndex++ ) {
            codePoint = _string.charCodeAt( stringIndex );

            if( codePoint < 0x100 ) {
                accum += 1;
                continue;
            }

            if( codePoint < 0x10000 ) {
                accum += 2;
                continue;
            }

            if( codePoint < 0x1000000 ) {
                accum += 3;
            } else {
                accum += 4;
            }
        }

        return accum * 2;
    }

Exemples:

getStringMemorySize( 'I'    );     //  2
getStringMemorySize( '❤'    );     //  4
getStringMemorySize( '????'   );     //  8
getStringMemorySize( 'I❤????' );     // 14
7
Mac

Notez que si vous ciblez node.js, vous pouvez utiliser Buffer.from(string).length :

var str = "\u2620"; // => "☠"
str.length; // => 1 (character)
Buffer.from(str).length // => 3 (bytes)
6
maerics

Vous pouvez utiliser le Blob pour obtenir la taille de la chaîne en octets.

Exemples:

console.info(
  new Blob(['????']).size,                             // 4
  new Blob(['????']).size,                             // 4
  new Blob(['????????']).size,                           // 8
  new Blob(['????????']).size,                           // 8
  new Blob(['I\'m a string']).size,                  // 12

  // from Premasagar correction of Lauri's answer for
  // strings containing lone characters in the surrogate pair range:
  // https://stackoverflow.com/a/39488643/6225838
  new Blob([String.fromCharCode(55555)]).size,       // 3
  new Blob([String.fromCharCode(55555, 57000)]).size // 4 (not 6)
);

5
P Roitto

La taille d'une chaîne JavaScript est

  • Pre-ES6: 2 octets par caractère 
  • ES6 et versions ultérieures: 2 octets par caractère, Ou 5 octets ou plus par caractère

Pre-ES6
Toujours 2 octets par caractère. UTF-16 n'est pas autorisé car la spécification indique que "les valeurs doivent être des entiers non signés 16 bits". Étant donné que les chaînes UTF-16 peuvent utiliser des caractères de 3 ou 4 octets, cela violerait l'exigence de 2 octets. De manière cruciale, bien que UTF-16 ne puisse pas être totalement pris en charge, la norme exige que les caractères à deux octets utilisés soient des caractères UTF-16 valides. En d'autres termes, les chaînes JavaScript pré-ES6 prennent en charge un sous-ensemble de caractères UTF-16 .

ES6 et ultérieur
2 octets par caractère, ou 5 octets ou plus par caractère. Les tailles supplémentaires entrent en jeu car ES6 (ECMAScript 6) ajoute la prise en charge de Les échappements de points de code Unicode . Utiliser un échappement Unicode ressemble à ceci:\u {1D306}

Notes pratiques 

  • Cela ne concerne pas la mise en œuvre interne d'un moteur particulier. Par exemple, certains moteurs utilisent des structures de données et des bibliothèques avec une prise en charge complète de UTF-16, mais ce qu'ils fournissent en externe ne doit pas obligatoirement être une prise en charge de Full UTF-16. De plus, un moteur peut également fournir une prise en charge UTF-16support externe, mais n'est pas obligé de le faire.

  • Pour ES6, les caractères ne seront jamais plus longs que 5 Octets (2 octets pour le point d’échappement + 3 octets pour le point de code Unicode ), Car la dernière version d’Unicode n’a que 136 755 caractères possibles. , qui s’intègre facilement dans 3 octets. Toutefois, techniquement, il n’est pas limité par la norme. Par conséquent, un seul caractère .__ pourrait utiliser, par exemple, 4 octets pour le point de code et 6 octetstotal.

  • La plupart des exemples de code présentés ici pour calculer la taille en octets ne semblent pas prendre en compte les échappements de points de code Unicode ES6. Par conséquent, les résultats peuvent être incorrects dans certains cas.

4
whitneyland

La réponse de Lauri Oherd fonctionne bien pour la plupart des chaînes vues dans la nature, mais échouera si la chaîne contient des caractères isolés dans la plage de paires de substitution, 0xD800 à 0xDFFF. Par exemple.

byteCount(String.fromCharCode(55555))
// URIError: URI malformed

Cette fonction plus longue devrait gérer toutes les chaînes:

function bytes (str) {
  var bytes=0, len=str.length, codePoint, next, i;

  for (i=0; i < len; i++) {
    codePoint = str.charCodeAt(i);

    // Lone surrogates cannot be passed to encodeURI
    if (codePoint >= 0xD800 && codePoint < 0xE000) {
      if (codePoint < 0xDC00 && i + 1 < len) {
        next = str.charCodeAt(i + 1);

        if (next >= 0xDC00 && next < 0xE000) {
          bytes += 4;
          i++;
          continue;
        }
      }
    }

    bytes += (codePoint < 0x80 ? 1 : (codePoint < 0x800 ? 2 : 3));
  }

  return bytes;
}

Par exemple.

bytes(String.fromCharCode(55555))
// 3

Il calculera correctement la taille des chaînes contenant des paires de substitution:

bytes(String.fromCharCode(55555, 57000))
// 4 (not 6)

Les résultats peuvent être comparés à la fonction intégrée de Node Buffer.byteLength:

Buffer.byteLength(String.fromCharCode(55555), 'utf8')
// 3

Buffer.byteLength(String.fromCharCode(55555, 57000), 'utf8')
// 4 (not 6)
2
Premasagar

Je travaille avec une version intégrée du moteur V8. J'ai testé une seule chaîne. En poussant chaque étape 1000 caractères. UTF-8. 

Premier test avec un octet (8 bits, ANSI) Caractère "A" (hex: 41) . Deuxième test avec un caractère sur deux octets (16 bits) "Ω" (hex: CE A9) et le troisième test .__ avec trois caractère octet (24 bits) "☺" (hex: E2 98 BA). 

Dans les trois cas, l’appareil imprime en mémoire saturée à 888 000 caractères et en utilisant env. 26 348 ko en RAM. 

Résultat: les caractères ne sont pas stockés dynamiquement. Et pas avec seulement 16 bits. - Ok, peut-être que pour mon cas (Embedded 128 Mo RAM Appareil, Moteur V8 C++/QT) - L'encodage des caractères n'a rien à voir avec la taille en RAM du moteur javascript. Par exemple. encodingURI, etc. n'est utile que pour la transmission et le stockage de données de haut niveau.

Intégré ou non, le fait est que les caractères ne sont pas seulement stockés en 16 bits . Malheureusement, je n'ai pas de réponse à 100%, ce que Javascript fait dans la zone de bas niveau . Btw. J'ai testé le même (premier test ci-dessus) avec un tableau de caractère "A" . Poussé 1000 éléments à chaque étape. (Exactement le même test. Vient de remplacer une chaîne de caractères dans un tableau). Et le système n'a plus de mémoire (voulue) après 10 416 Ko d’utilisation et une longueur de tableau de 1 337 000. Ainsi, le moteur javascript n’est pas simplement restreint. C'est un genre plus complexe. 

1
Dominik

Vous pouvez essayer ceci:

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

Cela a fonctionné pour moi.

1
user3728331

Un seul élément d'une chaîne JavaScript est considéré comme une seule unité de code UTF-16. C'est-à-dire que les caractères de chaîne sont stockés sur 16 bits (1 unité de code) et que 16 bits est égal à 2 octets (8 bits = 1 octet).

La méthode charCodeAt() peut être utilisée pour renvoyer un entier compris entre 0 et 65535 représentant l'unité de code UTF-16 à l'index donné.

codePointAt() peut être utilisé pour renvoyer la valeur entière du point de code pour les caractères Unicode, par exemple. UTF-32.

Lorsqu'un caractère UTF-16 ne peut pas être représenté dans une seule unité de code 16 bits, il aura une paire de substitution et utilisera donc deux unités de code (2 x 16 bits = 4 octets).

Voir Codages Unicode pour différents codages et leurs plages de codes.

0
holmberd