2010-05-17 16 views

Respuesta

12

edición: como Didier-l ha señalado, esta función no cuenta caracteres suplentes correctamente.

La respuesta de broofa debe contar los sustitutos correctamente, vea https://stackoverflow.com/a/12206089/274483.

He probado las dos versiones que aquí se propone, así como una aplicación ingenua:

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; 
} 

Con el resultado de que mi versión es ligeramente más rápido en Firefox y significativamente más rápido en cromo (~ 30x) que el aquí publicado versiones.

+5

No creo que esta implementación sea correcta, ya que cuenta dos veces los caracteres sustitutos: una cuando se encuentra con el sustituto alto y otra cuando se encuentra con la inferior. Por ejemplo, lo siguiente devuelve 6: getUTF8Length (String.fromCharCode (0xD800, 0xDC00)) aunque esto representa un solo carácter (debo admitir que no sé cuál, acabo de combinar 2 códigos de sustituto ...) . Aunque no soy un experto en Unicode ... –

+0

@Didier L, sí, tienes razón! Se debe agregar a la lista de casos y se debe tener en cuenta – Sebastian

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

Esto es bastante resbaladiza. El único problema es que arrojará si la cadena contiene un patrón sustituto no válido. P.ej. 'encodeURIComponent ('\ ud800a')'. Solo algo de lo que debes estar consciente. – broofa

+1

¿Cómo se puede insertar en textarea una cadena que contiene un patrón sustituto no válido? Intenté insertar el texto '\ ud800a' ​​en esta [página de prueba] (http://mothereff.in/byte-counter) (que usa la función 'encodeURI' internamente para codificar el texto insertado) pero no pude reproducir tal situación de error - en su lugar vi: 'document.getElementsByTagName (" textarea ") [0] .value ===" \\ ud800a "'. –

+0

Utilizado para contar la longitud del hilo UTF-8. –

0

Me he estado preguntando lo mismo. Esta es la mejor respuesta que he tropezar con:

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

Aquí es el fragmento de código:

<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) 
} 

pero el enlace contiene un ejemplo vivo de ella para jugar. "encodeURI (STRING)" es el componente básico aquí, pero también consulte encodeURIComponent (STRING) (como ya lo señalé en la respuesta anterior) para ver cuál se ajusta a sus necesidades.

Saludos

14

Si tiene caracteres no bmp en su cadena, que es un poco más complicado ...

Debido Javascript hace UTF-16 codificar, y un "carácter" es una de 2 bytes-pila (16 bits) todos los caracteres de varios bytes (3 y más bytes) no funcionarán:

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

El carácter "€" tiene una longitud de 3 bytes (24 bits). Javascript lo interpreta como 2 caracteres, porque en JS, un personaje es un bloque de 16 bits.

Para obtener correctamente el tamaño de bytes de una cadena mixta, tenemos que codificar nuestra propia función 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; 
    } 

Ahora podemos contar los bytes ...

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; 
    } 

Por cierto ... No use el encodeURI-método, ya que, se trata de una función de navegador nativo;)

más cosas:


Saludos

frankneff.ch/@frank_neff 
+0

Hola Frank, Utilicé tu método y funciona correctamente para cadenas de bytes de varios bytes. Tengo un área de texto donde necesito contar los caracteres/bytes tan pronto como los tipos de usuario. Probé el evento de pulsación de tecla pero no se dispara cuando hacemos copiar/pegar. ¿Puede sugerir alguna manera confiable y eficiente de contar los bytes mientras los tipos de usuario? Necesito mostrar un conteo como "300 quedan .." Gracias y saludos, Nadeem –

+0

No es necesario el' else if (charCode <67108864) {} 'bit y el' else' que lo sigue. Unicode se detiene en U + 10FFFF y es imposible representar un no -Unicode punto de código en JavaScript –

+0

Esto es cierto de acuerdo con la especificación RFC3629. Pero la especificación original permite hasta seis caracteres de bytes. No estoy seguro de qué implementación se debe respetar, pero yo diría que esta es la solución correcta. –

14

Combinando varias respuestas, el siguiente método debe ser rápida y precisa, y evita problemas con los pares suplentes no válidas que pueden causar errores en 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

Añadir función de conteo longitud en bytes de la cadena

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

entonces puede utilizar .Blength() para obtener el tamaño

1
¿Qué hay de

simple:

unescape(encodeURIComponent(utf8text)).length 

El truco es que encodeURIComponent parece funcionar en los personajes, mientras que unescape trabaja en bytes.

+0

la función 'unescape' es [d obsoleto y obsoleto a partir de JavaScript 1.5] (https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Functions#escape_and_unescape_functions (Obsoleted_above_JavaScript_1.5)) – jvatic

-1

intente lo siguiente:

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

conjunto meta UTF-8 simplemente & Está bien!

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

y JS:

if($mytext.length > 10){ 
// its okkk :) 
} 
Cuestiones relacionadas