2010-05-17 4 views

Répondre

12

edit: comme didier-l a souligné, cette fonction ne compte pas les caractères de substitution correctement.

La réponse de broofa devrait compter correctement les substituts, voir https://stackoverflow.com/a/12206089/274483.

J'ai testé les deux versions proposées ici, ainsi qu'une mise en œuvre naïve:

getUTF8Length: function(string) { 
    var utf8length = 0; 
    for (var n = 0; n < string.length; n++) { 
     var c = string.charCodeAt(n); 
     if (c < 128) { 
      utf8length++; 
     } 
     else if((c > 127) && (c < 2048)) { 
      utf8length = utf8length+2; 
     } 
     else { 
      utf8length = utf8length+3; 
     } 
    } 
    return utf8length; 
} 

Avec le résultat que ma version est légèrement plus rapide dans Firefox et nettement plus rapide en chrome (~ 30x) que le ici affiché versions.

+5

Je ne pense pas que cette implémentation soit correcte car elle compte deux fois les caractères de substitution: une fois en rencontrant le substitut haut, puis une fois en rencontrant la valeur basse. Par exemple, les retours suivants 6: getUTF8Length (String.fromCharCode (0xD800, 0xDC00)) bien que cela représente un seul caractère (je dois admettre que je ne sais pas lequel, je viens de combiner 2 codes de substitution de caractères ...) . Je ne suis pas expert en unicode ... –

+0

@Didier L, oui tu as raison! Il doit être ajouté à la liste des cas et être pris en compte – Sebastian

17
encodeURIComponent(text).replace(/%[A-F\d]{2}/g, 'U').length 
+2

Ceci est assez lisse. Le seul problème est qu'il va lancer si la chaîne contient un modèle de substitution invalide. Par exemple. 'encodeURIComponent ('\ ud800a')'. Juste quelque chose à savoir. – broofa

+1

Comment pouvez-vous insérer dans une zone de texte une chaîne contenant un modèle de substitution invalide? J'ai essayé d'insérer le texte '\ ud800a' ​​à cette [page de test] (http://mothereff.in/byte-counter) (qui utilise la fonction 'encodeURI' en interne pour encoder le texte inséré) mais n'a pas pu reproduire un tel situation d'erreur - à la place j'ai vu: 'document.getElementsByTagName (" textarea ") [0] .value ===" \\ ud800a "'. –

+0

Utilisé pour compter la longueur de la chaîne UTF-8. –

0

Je me suis demandé la même chose. C'est la meilleure réponse que je trébuche sur:

http://www.inter-locale.com/demos/countBytes.html

Voici l'extrait de code:

<script type="text/javascript"> 
function checkLength() { 
    var countMe = document.getElementById("someText").value 
    var escapedStr = encodeURI(countMe) 
    if (escapedStr.indexOf("%") != -1) { 
     var count = escapedStr.split("%").length - 1 
     if (count == 0) count++ //perverse case; can't happen with real UTF-8 
     var tmp = escapedStr.length - (count * 3) 
     count = count + tmp 
    } else { 
     count = escapedStr.length 
    } 
    alert(escapedStr + ": size is " + count) 
} 

mais le lien contient un exemple en direct de celui-ci à jouer avec. "encodeURI (STRING)" est le bloc de construction ici, mais regardez aussi encodeURIComponent (STRING) (comme déjà souligné sur la réponse précédente) pour voir lequel correspond à vos besoins.

Cordialement

14

Si vous avez des caractères non-bmp dans votre chaîne, il est un peu plus compliqué ...

Parce que le javascript ne code UTF-16, et un « caractère » est une pile de 2 octets (16 bits) tous les caractères multi-octets (3 et plus d'octets) ne fonctionneront pas:

<script type="text/javascript"> 
     var nonBmpString = "foo€"; 
     console.log(nonBmpString.length); 
     // will output 5 
    </script> 

Le caractère "€" a une longueur de 3 octets (24 bits). Javascript l'interprète comme 2 caractères, car dans JS, un caractère est un bloc de 16 bits. Donc pour obtenir correctement l'octet d'une chaîne mixte, nous devons coder notre propre fonction fixedCharCodeAt();

function fixedCharCodeAt(str, idx) { 
     idx = idx || 0; 
     var code = str.charCodeAt(idx); 
     var hi, low; 
     if (0xD800 <= code && code <= 0xDBFF) { // High surrogate (could change last hex to 0xDB7F to treat high private surrogates as single characters) 
      hi = code; 
      low = str.charCodeAt(idx + 1); 
      if (isNaN(low)) { 
       throw 'Kein gültiges Schriftzeichen oder Speicherfehler!'; 
      } 
      return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000; 
     } 
     if (0xDC00 <= code && code <= 0xDFFF) { // Low surrogate 
      // We return false to allow loops to skip this iteration since should have already handled high surrogate above in the previous iteration 
      return false; 
      /*hi = str.charCodeAt(idx-1); 
      low = code; 
      return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;*/ 
     } 
     return code; 
    } 

Maintenant, nous pouvons compter les octets ...

function countUtf8(str) { 
     var result = 0; 
     for (var n = 0; n < str.length; n++) { 
      var charCode = fixedCharCodeAt(str, n); 
      if (typeof charCode === "number") { 
       if (charCode < 128) { 
        result = result + 1; 
       } else if (charCode < 2048) { 
        result = result + 2; 
       } else if (charCode < 65536) { 
        result = result + 3; 
       } else if (charCode < 2097152) { 
        result = result + 4; 
       } else if (charCode < 67108864) { 
        result = result + 5; 
       } else { 
        result = result + 6; 
       } 
      } 
     } 
     return result; 
    } 

Soit dit en passant ... Vous ne devriez pas utiliser la encodeURI méthode, car, il est une fonction de navigateur natif;)

Plus de choses:


Vive

frankneff.ch/@frank_neff 
+0

Bonjour Frank, J'ai utilisé votre méthode et cela fonctionne correctement pour les chaînes de caractères multi-octets. J'ai une zone de texte où j'ai besoin de compter les caractères/octets dès que les types d'utilisateurs. J'ai essayé l'événement de presse de touche, mais il ne se fait pas virer quand on fait un copier/coller. Pouvez-vous s'il vous plaît suggérer un moyen fiable et efficace pour compter les octets pendant que l'utilisateur tape? J'ai besoin de montrer un compte comme "300 left .. Merci et salutations, Nadeem –

+0

Le bit 'else if (charCode <67108864) {}' et le 'else' qui le suit ne sont pas nécessaires.Unicode s'arrête à U + 10FFFF et il est impossible de représenter un non -Inicode point de code en JavaScript –

+0

Cela est vrai selon la spécification RFC3629 Mais la spécification d'origine permet jusqu'à six caractères octets.Je ne suis pas sûr quelle implémentation doit être respectée, mais je dirais que c'est la bonne solution –

14

En combinant diverses réponses, la méthode suivante doit être rapide et précis, et évite des problèmes avec des paires de substitution non valides qui peuvent provoquer des erreurs dans encodeURIComponent():

function getUTF8Length(s) { 
    var len = 0; 
    for (var i = 0; i < s.length; i++) { 
    var code = s.charCodeAt(i); 
    if (code <= 0x7f) { 
     len += 1; 
    } else if (code <= 0x7ff) { 
     len += 2; 
    } else if (code >= 0xd800 && code <= 0xdfff) { 
     // Surrogate pair: These take 4 bytes in UTF-8 and 2 chars in UCS-2 
     // (Assume next char is the other [valid] half and just skip it) 
     len += 4; i++; 
    } else if (code < 0xffff) { 
     len += 3; 
    } else { 
     len += 4; 
    } 
    } 
    return len; 
} 
0
encodeURI(text).split(/%..|./).length - 1 
1

Ajouter la longueur Byte fonction de comptage à la chaîne

String.prototype.Blength = function() { 
    var arr = this.match(/[^\x00-\xff]/ig); 
    return arr == null ? this.length : this.length + arr.length; 
} 

vous pouvez utiliser .Blength() pour obtenir la taille

1

Que diriez-vous simple:

unescape(encodeURIComponent(utf8text)).length 

L'astuce est que encodeURIComponent semble fonctionner sur des personnages tout en unescape fonctionne sur des octets.

+0

la fonction 'unescape' est [d eprecated et obsolète à partir de JavaScript 1.5] (https://developer.mozilla.org/fr-fr/docs/JavaScript/Guide/Functions#escape_and_unescape_functions (Obsoleted_above_JavaScript_1.5)) – jvatic

-1

les opérations suivantes:

function b(c) { 
    var n=0; 
    for (i=0;i<c.length;i++) { 
      p = c.charCodeAt(i); 
      if (p<128) { 
       n++; 
      } else if (p<2048) { 
       n+=2; 
      } else { 
       n+=3; 
      } 
     }return n; 
} 
-1

mis meta UTF-8 juste & il est OK!

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

et js:

if($mytext.length > 10){ 
// its okkk :) 
} 
Questions connexes