Codificación Java Unicode

Un char Java tiene 2 bytes (tamaño máximo de 65.536), pero hay 95.221 caracteres Unicode. ¿Esto significa que no puede manejar ciertos caracteres Unicode en una aplicación Java?

¿Esto se reduce a la encoding de caracteres que estás usando?

Puedes manejarlos a todos si eres lo suficientemente cuidadoso.

El char de Java es una unidad de código UTF-16 . Para los caracteres con punto de código> 0xFFFF, se codificará con 2 caracteres (un par suplente).

Ver http://www.oracle.com/us/technologies/java/supplementary-142654.html para saber cómo manejar esos caracteres en Java.

(Por cierto, en Unicode 5.2 hay 107.154 caracteres asignados de 1.114.112 espacios).

Java usa UTF-16 . Un solo char Java solo puede representar caracteres del plano multilingüe básico . Otros personajes deben ser representados por un par de dos caracteres sustitutos . Esto se ve reflejado por métodos de API como String.codePointAt() .

Y sí, esto significa que una gran cantidad de código Java se romperá de una forma u otra cuando se use con caracteres fuera del plano multilingüe básico.

Para agregar a las otras respuestas, algunos puntos para recordar:

  • Un char Java siempre toma 16 bits .

  • Un carácter Unicode , cuando está codificado como UTF-16, toma “casi siempre” (no siempre) 16 bits: eso es porque hay más de 64K caracteres Unicode. Por lo tanto, un carácter Java no es un carácter Unicode (aunque “casi siempre” lo es).

  • “Casi siempre”, arriba, significa los primeros 64K puntos de código de Unicode, rango 0x0000 a 0xFFFF ( BMP ), que toman 16 bits en la encoding UTF-16.

  • Un carácter Unicode no BMP (“raro”) se representa como dos caracteres de Java (representación sustituta). Esto se aplica también a la representación literal como una cadena: por ejemplo, el carácter U + 20000 se escribe como “\ uD840 \ uDC00”.

  • Corolary: string.length() devuelve el número de caracteres de Java, no de caracteres Unicode. Una cadena que tiene solo un carácter Unicode “raro” (por ejemplo, U + 20000) devolvería length() = 2 . La misma consideración se aplica a cualquier método que trate con secuencias de caracteres.

  • Java tiene poca inteligencia para tratar con caracteres Unicode que no son BMP como un todo. Hay algunos métodos de utilidad que tratan a los caracteres como puntos de código, representados por ejemplo: Character.isLetter(int ch) . Esos son los métodos reales totalmente Unicode.

Eche un vistazo al soporte de Unicode 4.0 en el artículo de J2SE 1.5 para aprender más sobre los trucos inventados por Sun para proporcionar soporte para todos los puntos de código de Unicode 4.0.

En resumen, encontrará los siguientes cambios para Unicode 4.0 en Java 1.5:

  • char es una unidad de código UTF-16, no un punto de código
  • nuevas API de bajo nivel usan una int para representar un punto de código Unicode
  • las API de alto nivel se han actualizado para comprender los pares de sustitución
  • una preferencia hacia las API de secuencia de caracteres en lugar de los métodos basados ​​en caracteres

Como Java no tiene caracteres de 32 bits, te dejaré juzgar si podemos llamar a este buen soporte Unicode.

Aquí está la documentación de Oracle sobre Representaciones de personajes de Unicode . O, si lo prefiere, una documentación más completa aquí .

El tipo de datos char (y, por lo tanto, el valor que encapsula un objeto Character) se basa en la especificación original Unicode, que define caracteres como entidades de 16 bits de ancho fijo. El estándar Unicode ha sido cambiado desde entonces para permitir caracteres cuya representación requiera más de 16 bits. El rango de puntos de código legal ahora es U + 0000 a U + 10FFFF, conocido como valor escalar Unicode. (Consulte la definición de la notación U + n en el estándar Unicode).

El conjunto de caracteres de U + 0000 a U + FFFF a veces se denomina Plano Básico Multilingüe (BMP). Los caracteres cuyos puntos de código son mayores que U + FFFF se llaman caracteres suplementarios. La plataforma Java 2 usa la representación UTF-16 en matrices char y en las clases String y StringBuffer. En esta representación, los caracteres suplementarios se representan como un par de valores char, el primero del rango de sustitutos altos, (\ uD800- \ uDBFF), el segundo del rango de sustitutos bajos (\ uDC00- \ uDFFF).

Por lo tanto, un valor de char representa los puntos de código de plano multilingüe básico (BMP), incluidos los puntos de código sustituto o las unidades de código de la encoding UTF-16. Un valor int representa todos los puntos de código Unicode, incluidos los puntos de código suplementarios. Los 21 bits más bajos (menos significativos) de int se utilizan para representar puntos de código Unicode y los 11 bits superiores (más significativos) deben ser cero. A menos que se especifique lo contrario, el comportamiento con respecto a los caracteres suplementarios y los valores de caracteres secundarios es el siguiente:

  • Los métodos que solo aceptan un valor de char no pueden admitir caracteres suplementarios. Tratan los valores de char de los rangos de sustitución como caracteres indefinidos. Por ejemplo, Character.isLetter (‘\ uD840’) devuelve false, aunque este valor específico si es seguido por cualquier valor de bajo sustituto en una cadena representaría una letra.
  • Los métodos que aceptan un valor int admiten todos los caracteres Unicode, incluidos los caracteres suplementarios. Por ejemplo, Character.isLetter (0x2F81A) devuelve verdadero porque el valor del punto de código representa una letra (un ideogtwig CJK).

De la documentación de OpenJDK7 para String :

Una Cadena representa una cadena en el formato UTF-16 en la que los caracteres suplementarios están representados por pares de sustitución (consulte la sección Representaciones de Caracteres Unicode en la clase de Caracteres para obtener más información). Los valores de índice se refieren a unidades de código de char, por lo que un carácter suplementario utiliza dos posiciones en una cadena.