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?
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.
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;
}
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.
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)
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
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
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)
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)
);
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.
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)
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.
Vous pouvez essayer ceci:
var b = str.match(/[^\x00-\xff]/g);
return (str.length + (!b ? 0: b.length));
Cela a fonctionné pour moi.
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.