2011-01-20 9 views
6

¡Hola a todos, acabo de comenzar a intentar aprender Java y me he encontrado con algo realmente confuso!Java Unicode Confusion

Estaba escribiendo un ejemplo del libro que estoy usando. Es para demostrar el tipo de datos char.

El código es el siguiente:

public class CharDemo 
{ 
public static void main(String [] args) 
{ 
char a = 'A'; 
char b = (char) (a + 1); 
System.out.println(a + b); 
System.out.println("a + b is " + a + b); 
int x = 75; 
char y = (char) x; 
char half = '\u00AB'; 
System.out.println("y is " + y + " and half is " + half); 
} 
} 

El bit que me confunde es la afirmación, char media = '\ u00AB'. El libro indica que \ u00AB es el código para el símbolo '1/2'. Como se describe, cuando compilo y ejecuto el programa desde cmd, el símbolo que se produce en esta línea es, de hecho, un '1/2'.

Así que todo parece estar funcionando como debería. Decidí jugar con el código y probar algunos unicodes diferentes. Busqué en Google varias tablas Unicode y encontré que ninguna de ellas es coherente con el resultado anterior.

En cada uno me pareció declaró que el código/u00AB no fuera por 'medio' y de hecho para esto:

http://www.fileformat.info/info/unic...r/ab/index.htm Entonces, ¿qué conjunto se JAVA con carácter, pensé que se suponía Unicode para ser solo eso, Uni, solo uno. He buscado durante horas y en ninguna parte puedo encontrar un juego de caracteres que indique que/u00AB es igual a 1/2, sin embargo, esto es lo que mi compilador de Java interpreta.

¡Debo perderme algo obvio aquí! ¡Gracias por cualquier ayuda!

+3

recomiendo este artículo para ayudar a entender el problema que estamos enfrentando: [El Absoluto Cada mínimo de desarrollo de software absolutamente, positivamente debe saber acerca de Unicode y juegos de caracteres] (http://www.joelonsoftware.com/articles/Unicode.html) –

Respuesta

2

Una cosa genial de Java es que se basa en unicode. Esto significa que puede usar caracteres de sistemas de escritura que no sean alfabetos en inglés (por ejemplo, símbolos chinos o matemáticos), no solo en cadenas de datos, sino también en nombres de funciones y variables.

Aquí hay un código de ejemplo que usa caracteres Unicode en nombres de clase y nombres de variables.

class 方 { 
    String 北 = "north"; 
    double π = 3.14159; 
} 

class UnicodeTest { 
    public static void main(String[] arg) { 
     方 x1 = new 方(); 
     System.out.println(x1.北); 
     System.out.println(x1.π); 
    } 
} 

Java se creó en la época en que el estándar Unicode tenía valores definidos para un conjunto de caracteres mucho más pequeño. En aquel entonces, se pensaba que los 16 bits serían más que suficientes para codificar todos los caracteres que alguna vez se necesitarían. Con eso en mente, Java fue diseñado para usar UTF-16. De hecho, el tipo de datos char se utilizó originalmente para poder representar un punto de código Unicode de 16 bits.

El juego de caracteres UTF-8 está especificado en RFC 2279;

Los conjuntos de caracteres UTF-16 se especifica en el RFC 2781

Los conjuntos de caracteres UTF-16 utilizan cantidades de dieciséis bits y, por tanto, son sensibles a la orden de bytes. En estas codificaciones, el orden de bytes de una secuencia puede indicarse mediante una marca de orden de bytes inicial representada por el carácter Unicode '\ uFEFF'. marcas de orden de bytes se manejan de la siguiente manera:

When decoding, the UTF-16BE and UTF-16LE charsets ignore byte-order marks; when encoding, they do not write byte-order marks. 

When decoding, the UTF-16 charset interprets a byte-order mark to indicate the byte order of the stream but defaults to big-endian if there is no byte-order mark; when encoding, it uses big-endian byte order and writes a big-endian byte-order mark. 

Also see this

+2

UTF-8 y UTF-16 ** no son ** juegos de caracteres; son dos codificaciones de ancho variable diferentes de ** el mismo juego de caracteres: ** Unicode. – tchrist

4

\u00ab El carácter no es el carácter 1/2; vea esto definitive code page del sitio web de Unicode.org.

Lo que está viendo es (creo) una consecuencia del uso del System.outPrintStream en una plataforma donde la codificación de caracteres predeterminada no es UTF-8 o Latin-1. Tal vez es algún juego de caracteres de Windows como lo sugiere la respuesta de @ axtavt? (También tiene una explicación plausible de por qué \u00ab se muestra como 1/2 ... y no un carácter "splat".)

(En Unicode y América-1, \00BD es el punto de código para el personaje 1/2.)

16

Es un problema bien conocido con la consola de codificación desajuste en plataformas Windows.

Java Runtime espera que la codificación utilizada por la consola del sistema sea la misma que la codificación predeterminada del sistema. Sin embargo, Windows usa dos codificaciones separadas: ANSI code page (system default encoding) and OEM code page (console encoding).

Por lo tanto, cuando intenta escribir caracteres Unicode U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK a la consola, de ejecución de Java espera que la consola de codificación es la codificación ANSI (es decir Windows-1252 en su caso), donde este carácter Unicode se representa como 0xAB. Sin embargo, la codificación de la consola real es la codificación OEM (CP437 en su caso), donde 0xAB significa .

Por lo tanto, la impresión de datos en la consola de Windows con System.out.println() produce resultados incorrectos.

Para obtener resultados correctos, puede usar System.console().writer().println() en su lugar.

+0

Gracias, esto tiene sentido, pero mencionas que imprimir datos a la consola de Windows produce resultados incorrectos. Este ejemplo fue directamente de un libro de Java, el escritor sabía que AB sería la mitad. ¿Es esto solo una mala escritura porque no explicó esto? – Nick

+1

@Nick: Entonces es una escritura pobre. Tal vez el autor rara vez trabajó con cartas que no sean estadounidenses y, por lo tanto, no estaba familiarizado con este problema. – axtavt

+1

+1. Es tonto realmente. Tanto Java como Windows usan cadenas nativas de Unicode codificadas en memoria como UTF-16LE. Y, sin embargo, siguen siendo incapaces de comunicarse entre sí sin pasar por un ciclo de decodificación y codificación de caracteres a través de bytes. – bobince

3

0xAB es 1/2 en el antiguo Codepage 437, que es lo que los terminales de Windows usarán por defecto, no matter what codepage you actually set.

De hecho, el valor char representa el carácter "« "de un programa Java, y si representa ese carácter en una GUI o lo ejecuta en un sistema operativo sano, obtendrá ese carácter. Si también desea ver la salida adecuada en Windows, cambie la configuración de Fuente en CMD de "Fuentes de mapa de bits" (haga clic en el ícono de arriba a la izquierda, Propiedades, pestaña Fuente). Por ejemplo, con Lucida Console, puedo hacer esto:

C:\Users\Documents>java CharDemo 
131 
a + b is AB 
y is K and half is ½  

C:\Users\Documents>chcp 1252 
Active code page: 1252 

C:\Users\Documents>java CharDemo 
131 
a + b is AB 
y is K and half is « 

C:\Users\Documents>chcp 437 
Active code page: 437 
+2

Oh, y venza al autor de su libro en la cabeza con él si alguna vez se encuentra con él/ella. – themel

+0

¿Alguna recomendación para un libro diferente? Sin embargo, absolutamente tiene que comenzar desde el principio, los conceptos básicos y fundamentales y más. – Nick