2011-05-05 24 views
107

Estaba leyendo la documentación para StringBuffer, en particular el método reverse(). Esa documentación menciona algo sobre pares de sustitución. ¿Qué es un par suplente en este contexto? ¿Y cuáles son bajo y alto sustitutos?¿Qué es un "par suplente" en Java?

+1

Es UTF-16 terminología, se explica aquí: http://download.oracle.com/javase/6/docs/api/java/lang/Character.html#unicode – birryree

+0

Ese método está libre de errores: se debería revertir personajes llenos ᴀᴋᴀ puntos de código - * no * partes separadas de ellos, ᴀᴋᴀ unidades de código. El error es que ese método heredado en particular funciona solo en unidades de caracteres individuales en lugar de en puntos de código, que es lo que * desea * '' cadena '' que se compone, no solo de unidades de caracteres. Lástima que Java no le permita usar OO para arreglar eso, pero tanto la clase 'String' como las clases' StringBuffer' han sido 'final''. Diga, ¿no es eso un eufemismo para matar? :) – tchrist

+2

@tchrist La documentación (y la fuente) dice que se invierte como una cadena de puntos de código. (Es de suponer que 1.0.2 no hizo eso, y nunca obtendría ese cambio de comportamiento en estos días). –

Respuesta

88

El término "par suplente" se refiere a un medio de codificación de caracteres Unicode con altos puntos de código en el esquema de codificación UTF-16.

En la codificación de caracteres Unicode, los caracteres se asignan a valores entre 0x0 y 0x10FFFF.

Internamente, Java usa el esquema de codificación UTF-16 para almacenar cadenas de texto Unicode. En UTF-16, se usan unidades de código de 16 bits (dos bytes). Como 16 bits solo pueden contener el rango de caracteres de 0x0 a 0xFFFF, se usa cierta complejidad adicional para almacenar valores por encima de este rango (0x10000 a 0x10FFFF). Esto se hace usando pares de unidades de código conocidas como sustitutos.

Las unidades de código sustituto están en dos rangos conocidos como "sustitutos altos" y "sustitutos bajos", dependiendo de si están permitidos al principio o al final de la secuencia de dos unidades de código.

22

Lo que la documentación está diciendo es que no válidas UTF-16 cuerdas pueden llegar a ser válida después de llamar al método reverse ya que podrían ser los reveses de cadenas válidas Un par sustituto (discutido here) es un par de valores de 16 bits en UTF-16 que codifican un único punto de código Unicode; los sustitutos bajos y altos son las dos mitades de esa codificación.

+6

Aclaración. Una cadena debe invertirse en caracteres "verdaderos" (a.k.a "grafemas" o "elementos de texto"). Un único punto de código "carácter" podría ser uno o dos fragmentos "char" (par suplente), y un grafema podría ser uno o más de esos puntos de código (es decir, un código de carácter base más uno o más códigos de carácter combinados, cada uno podría ser uno o dos trozos de 16 bits o "caracteres" largos). Así que un solo grafema podría ser tres caracteres que combinen cada dos "caracteres" de largo, totalizando 6 "caracteres". Los 6 "caracteres" se deben mantener juntos, en orden (es decir, no invertido), cuando se invierte toda la secuencia de caracteres. – Triynko

+4

Por lo tanto, el tipo de datos "char" es bastante engañoso. "personaje" es un término informal. El tipo "char" es realmente solo el tamaño de fragmento UTF16 y lo llamamos carácter debido a la relativa rareza de pares sustitutos (es decir, generalmente representa un punto de código de carácter completo), por lo que "personaje" realmente se refiere a un único punto de código Unicode , pero luego con los caracteres que se combinan, puede tener una secuencia de caracteres que se muestran como un único "elemento de carácter/grafema/texto". Esto no es ciencia de cohetes; los conceptos son simples, pero el lenguaje es confuso. – Triynko

+0

En el momento en que Java se estaba desarrollando, Unicode estaba en su infancia. Java existía alrededor de 5 años antes de que Unicode obtuviera pares de sustitución, por lo que un char de 16 bits encajaba bastante bien en ese momento. Ahora, es mucho mejor usar UTF-8 y UTF-32 que UTF-16. –

1

Un par suplente es dos 'unidades de código' en UTF-16 que constituyen un 'punto de código'. La documentación de Java indica que estos 'puntos de código' seguirán siendo válidos, con sus 'unidades de código' ordenadas correctamente, después del reverso. Además establece que dos unidades de código sustituto no emparejadas pueden invertirse y formar un par sustituto válido. Lo que significa que si hay unidades de código sin emparejar, ¡existe la posibilidad de que el reverso del reverso no sea el mismo!

Sin embargo, tenga en cuenta que la documentación no dice nada acerca de Graphemes, que son varios puntos de código combinados. Lo que significa que e y el acento que lo acompaña todavía pueden cambiarse, colocando así el acento antes de la e. Lo que significa que si hay otra vocal antes de la e, puede obtener el acento que estaba en la e.

¡Yikes!

5

Las primeras versiones de Java representaban caracteres Unicode utilizando el tipo de datos char de 16 bits. Este diseño tenía sentido en ese momento, porque todos los caracteres Unicode tenían valores inferiores a 65.535 (0xFFFF) y podían representarse en 16 bits. Más tarde, sin embargo, Unicode aumentó el valor máximo a 1,114,111 (0x10FFFF). Como los valores de 16 bits eran demasiado pequeños para representar todos los caracteres Unicode en la versión 3.1 de Unicode, se adoptaron valores de 32 bits, llamados puntos de código, para el esquema de codificación UTF-32. Pero los valores de 16 bits se prefieren a los valores de 32 bits para un uso eficiente de la memoria, por lo que Unicode presentó un nuevo diseño para permitir el uso continuo de los valores de 16 bits. Este diseño, adoptado en el esquema de codificación UTF-16, asigna 1.024 valores a sustitutos altos de 16 bits (en el rango U + D800 a U + DBFF) y otros 1.024 valores a sustitutos bajos de 16 bits (en el rango U + DC00 a U + DFFF). Utiliza un subrogado alto seguido de un sustituto bajo, un par sustituto, para representar (el producto de 1,024 y 1,024) valores de 1,048,576 (0x100000) entre 65,536 (0x10000) y 1,114,111 (0x10FFFF).

+0

Me gusta más que la respuesta aceptada, ya que explica cómo Unicode 3.1 reservó valores 1024 + 1024 (alto + bajo) del 65535 original para obtener 1024 * 1024 nuevos valores, sin requisitos adicionales de que los analizadores comiencen al principio de una cuerda. –