2011-03-27 15 views
13

Necesito obtener una cadena/char de un código de caracteres unicode y finalmente ponerlo en un DOM TextNode para agregarlo a una página HTML utilizando JavaScript del lado del cliente.Caracteres Unicode del código de caracteres en javascript para los códigos de caracteres> 0xFFFF

Actualmente, estoy haciendo:

String.fromCharCode(parseInt(charcode, 16)); 

donde charcode es una cadena hexadecimal que contiene el charCode, por ejemplo, "1D400". El carácter Unicode que se debe devolver es , pero se devuelve . Los caracteres en el rango de 16 bits (0000 ... FFFF) se devuelven como se esperaba.

¿Alguna explicación y/o propuesta de corrección?

¡Gracias de antemano!

+3

He aquí una explicación detallada: http://mathiasbynens.be/notes/javascript-encoding –

Respuesta

14

El problema es que los personajes de JavaScript son (mostly) UCS-2 encoded pero pueden representar un carácter fuera del plano básico multilingüe en JavaScript como una UTF-16 par suplente.

La función siguiente es una adaptación de Converting punycode with dash character to Unicode:

function utf16Encode(input) { 
    var output = [], i = 0, len = input.length, value; 
    while (i < len) { 
     value = input[i++]; 
     if ((value & 0xF800) === 0xD800) { 
      throw new RangeError("UTF-16(encode): Illegal UTF-16 value"); 
     } 
     if (value > 0xFFFF) { 
      value -= 0x10000; 
      output.push(String.fromCharCode(((value >>>10) & 0x3FF) | 0xD800)); 
      value = 0xDC00 | (value & 0x3FF); 
     } 
     output.push(String.fromCharCode(value)); 
    } 
    return output.join(""); 
} 

alert(utf16Encode([0x1D400])); 
+0

Aunque utilicé el código (más corto) de Anomie, acepté su solución ya que su código hace una buena comprobación de errores (pero no lo necesito) – leemes

+0

Tenga en cuenta que la terminología correcta es simplemente la codificación 'UTF-16'. Esto asigna uno a uno a 'UCS-2' para los primeros 65536 caracteres, a excepción de los sustitutos. Pero por lo que podemos ver en tu código, es simplemente "UTF-16". –

+0

@AlexisWilke: No del todo. Los caracteres de JavaScript no están expuestos como UCS-2 o UTF-16 realmente: es idéntico a UCS-2, excepto que se permiten sustitutos. No es UTF-16 porque se permiten sustitutos y sustitutos inigualables en el orden incorrecto. Es solo cuando se renderiza el personaje en el navegador que los sustitutos del estilo UTF-16 se combinan en un único carácter Unicode. Aquí hay un buen artículo para el fondo: https://mathiasbynens.be/notes/javascript-encoding –

16

String.fromCharCode solo puede manejar puntos de código en el BMP (es decir, hasta U + FFFF). Para hacer frente a los puntos de código más altas, esta función desde Mozilla Developer Network se puede usar para devolver la representación par suplente:

function fixedFromCharCode (codePt) { 
    if (codePt > 0xFFFF) { 
     codePt -= 0x10000; 
     return String.fromCharCode(0xD800 + (codePt >> 10), 0xDC00 + (codePt & 0x3FF)); 
    } else { 
     return String.fromCharCode(codePt); 
    } 
} 
+0

Así que las cadenas de JScript están codificadas en UTF-16, y este fragmento de código es una conversión de código de caracteres => UTF-16, según tengo entendido ... Esperaba que el problema (y la solución) fuera algo como esto. ¡Funcionó! Tanques! – leemes

+0

Intenté esto y obtuve un "error de conversión de caracteres", pero me di cuenta de que el archivo de script estaba codificado en utf-8; cuando cambié la codificación a ucs2 (notepad ++) funcionó. – bgmCoder

9

Sección 8.4 de la especificación del lenguaje ECMAScript dice

Cuando una cadena contiene datos de texto reales, cada elemento se considera que es un solo UTF -16 unidad de código. Independientemente de que este sea el formato de almacenamiento real de una Cadena, los caracteres dentro de una Cadena se numeran por su posición inicial del elemento de la unidad de código como si estuvieran representados mediante UTF-16. Todas las operaciones en Strings (excepto que se indique lo contrario) las tratan como secuencias de enteros sin signo de 16 bits indiferenciados; no garantizan que la cadena resultante esté en forma normalizada, ni garantizan resultados sensibles al lenguaje.

Así que debe codificar los puntos de código suplementarios como pares de unidades de código UTF-16.

El artículo "Supplementary Characters in the Java Platform" ofrece una buena descripción de cómo hacer esto.

UTF-16 utiliza secuencias de una o dos unidades de código de 16 bits sin signo para codificar puntos de código Unicode. Los valores U + 0000 a U + FFFF están codificados en una unidad de 16 bits con el mismo valor. Los caracteres suplementarios están codificados en dos unidades de código, la primera del rango de sustitutos altos (U + D800 a U + DBFF), la segunda del rango de sustitutos bajos (U + DC00 a U + DFFF). Esto puede parecer similar en concepto a las codificaciones multibyte, pero hay una diferencia importante: los valores U + D800 a U + DFFF están reservados para su uso en UTF-16; no se les asignan caracteres como puntos de código. Esto significa que el software puede determinar para cada unidad de código individual en una cadena si representa un carácter de una unidad o si es la primera o la segunda unidad de un carácter de dos unidades. Esta es una mejora significativa con respecto a algunas codificaciones de caracteres multibyte tradicionales, donde el valor de byte 0x41 podría significar la letra "A" o ser el segundo byte de un carácter de dos bytes.

La siguiente tabla muestra las diferentes representaciones de unos pocos caracteres en comparación:

puntos de código/UTF-16 unidades de código

U + 0041/0041

U + 00DF/00DF

U + 6771/6771

U + 10400/D801 DC00

Una vez que conozca las unidades de código UTF-16, puede crear una cadena utilizando la función de JavaScript String.fromCharCode:

String.fromCharCode(0xd801, 0xdc00) === '' 
+0

¡Gracias por esta explicación detallada! Me hizo entender el comportamiento de las cadenas de JScript más profundo. Parece que la descripción de fromCharCode es incorrecta en el siguiente documento de w3schools, ya que solo dice "valor Unicode", pero 0x1A000 también es un "valor Unicode": [W3Schools: fromCharCode()] (http: // www. w3schools.com/jsref/jsref_fromCharCode.asp) – leemes

+2

+1 para citar la especificación del idioma. – Anomie

+0

@leemes, ya que estoy citando la especificación: "15.5.3.2 \t String.fromCharCode ([char0 [, char1 [, ...]]]) Devuelve un valor de cadena que contiene tantos caracteres como la cantidad de argumentos. Cada argumento especifica un carácter de la Cadena resultante, con el primer argumento que especifica el primer carácter, y así sucesivamente, de izquierda a derecha. Un argumento se convierte en un carácter aplicando la operación ToUint16 (9.7) y con respecto a los 16 bits resultantes entero como el valor de la unidad de código de un carácter. Si no se proporcionan argumentos, el resultado es la cadena vacía ". –

Cuestiones relacionadas