Discussion:
Connaître la longueur UTF-8 d'une chaîne JavaScript
(trop ancien pour répondre)
Olivier Miakinen
2015-01-01 18:11:03 UTC
Permalink
[diapublication avec f.c.n.unicode, suivi dans f.c.l.javascript seul]

Bonjour,

En JavaScript, les chaînes de caractères sont représentées en interne
dans le charset UTF-16, et c'est lors des interactions avec l'extérieur
(par exemple une requête AJAX ou XMLHttpRequest) qu'elles sont traduites
en UTF-8.

Je voudrais, dans JavaScript, savoir quelle sera la longueur d'une
chaîne en nombre d'octets une fois traduite en UTF-8. Je sais que la
propriété 'length' ne donne pas la bonne valeur (c'est le nombre de
seizets UTF-16). Comment puis-je faire ?

Cordialement,
--
Olivier Miakinen
Xavier Roche
2015-01-03 16:27:26 UTC
Permalink
Post by Olivier Miakinen
Je voudrais, dans JavaScript, savoir quelle sera la longueur d'une
chaîne en nombre d'octets une fois traduite en UTF-8. Je sais que la
propriété 'length' ne donne pas la bonne valeur (c'est le nombre de
seizets UTF-16). Comment puis-je faire ?
Il n'y a pas de solution simple AMHA, a part parcourir tous les
caractères, et tester les intervalles: (tests a effectuer dans cet ordre)

[ 0xD800 .. 0xDC00 [ : ajouter 4
[ 0xDC00 .. 0xE000 [ : ne rien faire
[ 0x0000 .. 0x007F [ : ajouter 1
[ 0x0080 .. 0x07FF [ : ajouter 2
[ 0x0800 .. 0xFFFF [ : ajouter 3

L'idée étant que l'on peut prendre en compte uniquement les "high
surrogates" qui donneront un point supérieur a FFFF (donc 4 octets) et
ignorer les "low surrogates".

Mais il y a peut être un solution plus efficace ...

Voir:
http://en.wikipedia.org/wiki/UTF-8#Description
http://en.wikipedia.org/wiki/UTF-16
Olivier Miakinen
2015-01-03 23:06:10 UTC
Permalink
Post by Xavier Roche
Post by Olivier Miakinen
Je voudrais, dans JavaScript, savoir quelle sera la longueur d'une
chaîne en nombre d'octets une fois traduite en UTF-8. Je sais que la
propriété 'length' ne donne pas la bonne valeur (c'est le nombre de
seizets UTF-16). Comment puis-je faire ?
Il n'y a pas de solution simple AMHA, a part parcourir tous les
caractères, et tester les intervalles: (tests a effectuer dans cet ordre)
[ 0xD800 .. 0xDC00 [ : ajouter 4
[ 0xDC00 .. 0xE000 [ : ne rien faire
[ 0x0000 .. 0x007F [ : ajouter 1
[ 0x0080 .. 0x07FF [ : ajouter 2
[ 0x0800 .. 0xFFFF [ : ajouter 3
L'idée étant que l'on peut prendre en compte uniquement les "high
surrogates" qui donneront un point supérieur a FFFF (donc 4 octets) et
ignorer les "low surrogates".
Mais il y a peut être un solution plus efficace ...
Tu viens de me donner une idée...

var re = /([\u0080-\u07FF\uD800-\uDFFF])|([\u0800-\uFFFF])/g;
var length = str.replace(re, "$1$1$2$2$2").length;

Je double tous les caractères dans la zone U+0080 .. U+07FF ainsi
que tous les surrogates (high et low), et je triple ceux de la
zone U+0800 .. U+FFFF, puis j'en demande la longueur.

Ainsi, un "e" reste "e", un "é" devient "éé", un "€" devient "€€€",
et un "𝄞" c'est-à-dire "\ud834\udd1e" devient "\ud834𝄞\udd1e"
c'est-à-dire "\ud834\ud834\udd1e\udd1e". Dans tous les cas j'obtiens
le bon nombre de caractères !
Hibou57 (Yannick Duchêne)
2015-02-08 17:54:34 UTC
Permalink
Post by Olivier Miakinen
[diapublication avec f.c.n.unicode, suivi dans f.c.l.javascript seul]
Bonjour,
En JavaScript, les chaînes de caractères sont représentées en interne
dans le charset UTF-16, et c'est lors des interactions avec l'extérieur
(par exemple une requête AJAX ou XMLHttpRequest) qu'elles sont traduites
en UTF-8.
Je voudrais, dans JavaScript, savoir quelle sera la longueur d'une
chaîne en nombre d'octets une fois traduite en UTF-8. Je sais que la
propriété 'length' ne donne pas la bonne valeur (c'est le nombre de
seizets UTF-16). Comment puis-je faire ?
Cordialement,
--
Olivier Miakinen
Bonsoir,

À partir de la valeur scalaire d'un caractère (son code, si tu préfère), tu peux connaitre l'espace en octet occupé par ce caractère dans l'encodage UTF-8, en reprenant la table donnée dans la spécification Unicode :
http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G7404
Vois les tables 3-6 et 3-7.

Pour le rapporter directement ici :

Intervalle hexadécimal / taille en octet(s)
U+0000..U+007F : 1 octet
U+0080..U+07FF : 2 octets
U+0800..U+0FFF : 3 octets
U+1000..U+CFFF : 3 octets
U+D000..U+D7FF : 3 octets
U+E000..U+FFFF : 3 octets
U+10000..U+3FFFF : 4 octets
U+40000..U+FFFFF : 4 octets
U+100000..U+10FFFF : 4 octets

Pour connaitre la valeur scalaire d'un caractère à la position `i` dans un chaîne en JavaScript, tu peux faire `scalaire = maChaine.charCodeAt(i);`.

Pour anecdote (pas dit que ça sera pertinent dans le cas présent), il ne faut pas oublier que certains caractères peut être représentés de plusieurs manières dans Unicode : forme normalisée, décomposée, composée, comme expliqué dans l'annexe #15, http://unicode.org/reports/tr15/ . Une conséquence est qu'une même chaîne pourra éventuellement voir des longueurs en octet différentes, selon les conventions adoptées, et que celle que tu déterminera en utilisant la table plus haut, ne sera pas universelle.

P.S. UTF-16 n'est pas un "charset", c'est un format d'encodage . Tu
peux trouver un exposé détaillé de cette question et d'autres associées, ici : http://bulleforum.net/decodeur-encodeur-unicode-en-ada-t4295.html .
Olivier Miakinen
2015-02-08 21:23:00 UTC
Permalink
Bonjour, et merci de ta réponse.
Post by Hibou57 (Yannick Duchêne)
Post by Olivier Miakinen
En JavaScript, les chaînes de caractères sont représentées en interne
dans le charset UTF-16, et c'est lors des interactions avec l'extérieur
(par exemple une requête AJAX ou XMLHttpRequest) qu'elles sont traduites
en UTF-8.
Je voudrais, dans JavaScript, savoir quelle sera la longueur d'une
chaîne en nombre d'octets une fois traduite en UTF-8. Je sais que la
propriété 'length' ne donne pas la bonne valeur (c'est le nombre de
seizets UTF-16). Comment puis-je faire ?
http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G7404
Vois les tables 3-6 et 3-7.
Certes, mais faire une boucle en JavaScript pour traiter chaque
caractère séparément serait beaucoup trop inefficace sur des chaînes
très longues. C'est pourquoi je cherchais soit une fonction JavaScript
native, soit une astuce comme celle de la regexp qui en un seul appel
transforme une chaîne JavaScript en une autre dont la propriété length
soit le nombre d'octets UTF-8.
Post by Hibou57 (Yannick Duchêne)
Intervalle hexadécimal / taille en octet(s)
U+0000..U+007F : 1 octet
U+0080..U+07FF : 2 octets
U+0800..U+0FFF : 3 octets
U+1000..U+CFFF : 3 octets
U+D000..U+D7FF : 3 octets
U+E000..U+FFFF : 3 octets
U+10000..U+3FFFF : 4 octets
U+40000..U+FFFFF : 4 octets
U+100000..U+10FFFF : 4 octets
En résumé :

U+0000..U+007F : 1 octet
U+0080..U+07FF : 2 octets
U+0800..U+FFFF : 3 octets
U+10000..U+10FFFF : 4 octets

... sans oublier que ce qui donne 4 octets en UTF-8 est représenté
par 2 seizets en UTF-16 au lieu d'1 pour les autres caractères.
Post by Hibou57 (Yannick Duchêne)
Pour connaitre la valeur scalaire d'un caractère à la position `i` dans un chaîne en JavaScript, tu peux faire `scalaire = maChaine.charCodeAt(i);`.
Oui, mais je préfère un seul str.replace() suivi d'un seul .length
plutôt que de devoir faire potentiellement plusieurs milliers ou
dizaines de milliers de charCodeAt().
Post by Hibou57 (Yannick Duchêne)
Pour anecdote (pas dit que ça sera pertinent dans le cas présent), il ne faut pas oublier que certains caractères peut être représentés de plusieurs manières dans Unicode : forme normalisée, décomposée, composée, comme expliqué dans l'annexe #15, http://unicode.org/reports/tr15/ . Une conséquence est qu'une même chaîne pourra éventuellement voir des longueurs en octet différentes, selon les conventions adoptées, et que celle que tu déterminera en utilisant la table plus haut, ne sera pas universelle.
Oui, et en effet ce n'est pas pertinent : la traduction de UTF-16 vers
UTF-8 se fait sans aucune renormalisation ; un caractère précomposé le
restera, de même qu'un caractère en forme décomposée.
Post by Hibou57 (Yannick Duchêne)
P.S. UTF-16 n'est pas un "charset", c'est un format d'encodage .
Je suis désolé, mais je ne suis pas d'accord. Certes ce n'est pas un
simple répertoire de caractères comme l'est Unicode, mais c'est bien
un « charset » selon MIME et l'IANA, et bien sûr selon la norme
définissant UTF-16 lui-même.

MIME :
https://tools.ietf.org/html/rfc2045#section-2.2

IANA :
http://www.iana.org/assignments/character-sets/character-sets.xhtml
<cit.>
Post by Hibou57 (Yannick Duchêne)
UTF-16BE 1013 [RFC2781] [RFC2781] csUTF16BE
UTF-16LE 1014 [RFC2781] [RFC2781] csUTF16LE
UTF-16 1015 [RFC2781] [RFC2781] csUTF16
</cit.>

Définition d'UTF-16 :
http://tools.ietf.org/html/rfc2781#section-1
<cit.>
This document [...] contains the registration for three
MIME charset parameter values: UTF-16BE (big-endian), UTF-16LE
(little-endian), and UTF-16.
</cit.>
Post by Hibou57 (Yannick Duchêne)
Tu
peux trouver un exposé détaillé de cette question et d'autres associées, ici : http://bulleforum.net/decodeur-encodeur-unicode-en-ada-t4295.html .
Je ne peux pas lire ce lien directement, et j'ai la flemme de configurer
mon bloqueur de pubs pour y accéder alors qu'il existe tellement de
ressources complètement gratuites (et plus officielles) sur le sujet.
Cf. supra. De toute manière, s'il contredit la norme, c'est qu'il ne
vaut pas vraiment la peine d'y aller...

Cordialement,
--
Olivier Miakinen
Loading...