Путаница в Java Unicode

Привет всем, я только начал попытки изучить Java и наткнулся на кое-что, что действительно сбивает с толку!

Я печатал пример из книги, которую использую. Он предназначен для демонстрации типа данных char.

Код выглядит следующим образом:

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

Меня смущает утверждение char half = '\ u00AB'. В книге указано, что \ u00AB - это код символа "1/2". Как описано, когда я компилирую и запускаю программу из cmd, в этой строке появляется символ «1/2».

Так что вроде все работает как надо. Я решил поиграться с кодом и попробовать разные юникоды. Я погуглил несколько таблиц Unicode и не обнаружил, что ни одна из них не соответствует приведенному выше результату.

В каждом найденном мной коде говорилось, что код / ​​u00AB не предназначен для 1/2, а на самом деле предназначен для этого:

http://www.fileformat.info/info/unic...r/ab/index.htm Итак, какой набор символов использует Java, я думал, что UNicode должен быть именно таким, Uni, только одним. Я искал несколько часов и нигде не нашел набора символов, в котором указано, что / u00AB равно 1/2, но это то, что мой компилятор java интерпретирует как.

Должно быть, я упускаю что-то очевидное! Спасибо за любую помощь!


person Nick    schedule 20.01.2011    source источник
comment
Я рекомендую эту статью, чтобы помочь понять проблему, с которой вы столкнулись: Абсолютный минимум, каждый разработчик программного обеспечения Абсолютно, Необходимо обязательно знать о Юникоде и наборах символов   -  person Adam Paynter    schedule 20.01.2011


Ответы (5)


Это хорошо известная проблема несоответствия кодировки консоли на платформах Windows.

Среда выполнения Java ожидает, что кодировка, используемая системной консолью, такая же, как кодировка системы по умолчанию. Однако в Windows используются две отдельные кодировки: кодовая страница ANSI (кодировка по умолчанию) и кодовая страница OEM (кодировка консоли).

Итак, когда вы пытаетесь записать символ Юникода U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK в консоль, среда выполнения Java ожидает, что кодировка консоли будет кодировкой ANSI (то есть Windows -1252 в вашем случае), где этот символ Юникода представлен как 0xAB. Однако фактическая кодировка консоли - это OEM-кодировка (CP437 в вашем случае), где 0xAB означает ½.

Поэтому печать данных в консоли Windows с System.out.println() дает неверные результаты.

Чтобы получить правильные результаты, вы можете использовать вместо этого System.console().writer().println().

person axtavt    schedule 20.01.2011
comment
Спасибо, это имеет смысл, но вы упомянули, что печать данных в консоли Windows дает неверные результаты. Этот пример взят прямо из книги по Java, писатель знал, что AB будет половиной. Это просто плохое письмо в том смысле, что он этого не объяснил? - person Nick; 20.01.2011
comment
@Nick: Тогда это плохое письмо. Возможно, автор редко работал с буквами, отличными от us-ascii, и поэтому не был знаком с этой проблемой. - person axtavt; 20.01.2011
comment
+1. Это действительно глупо. И Java, и Windows используют строки собственного Unicode, закодированные в памяти как UTF-16LE. И все же они по-прежнему не могут разговаривать друг с другом без прохождения цикла кодирования-декодирования с изменением символов через байты. - person bobince; 21.01.2011

Символ \u00ab не является символом 1/2; см. эту окончательную кодовую страницу с Unicode.org Веб-сайт.

То, что вы видите (я думаю), является следствием использования System.out PrintStream на платформе, где кодировка символов по умолчанию не является UTF-8 или Latin-1. Может быть, это какой-то набор символов Windows, предложенный ответом @ axtavt? (В нем также есть правдоподобное объяснение того, почему \u00ab отображается как 1/2 ... а не какой-то символ "splat".)

(В Unicode и Latin-1 \00BD - это код для символа 1/2.)

person Stephen C    schedule 20.01.2011

0xAB - это 1/2 в старом-добром кодовой странице 437, которую терминалы Windows будут использовать по умолчанию. , независимо от того, какую кодовую страницу вы фактически установили.

Фактически, значение char представляет собой символ «« »для Java-программы, и если вы отобразите этот символ в графическом интерфейсе или запустите его в нормальной операционной системе, вы получите этот символ. Если вы хотите видеть правильный вывод и в Windows, переключите настройки шрифта в CMD с «Растровые шрифты» (щелкните значок в верхнем левом углу, «Свойства», вкладку «Шрифт»). Например, с помощью Lucida Console я могу сделать это:

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
person themel    schedule 20.01.2011
comment
Да, и бейте им по голове автора вашей книги, если вы когда-нибудь встретите его / ее. - person themel; 20.01.2011
comment
Есть ли рекомендации по поводу другой книги? Это абсолютно должно начинаться с самого начала, с самых основ, основ и выше. - person Nick; 20.01.2011

В Java замечательно то, что она основана на юникоде. Это означает, что вы можете использовать символы из систем письма, не являющиеся английскими алфавитами (например, китайские или математические символы), не только в строках данных, но и в именах функций и переменных.

Вот пример кода с использованием символов Юникода в именах классов и именах переменных.

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 была создана примерно в то время, когда в стандарте Unicode были определены значения для гораздо меньшего набора символов. Тогда считалось, что 16 бит будет более чем достаточно для кодирования всех символов, которые когда-либо понадобятся. Имея это в виду, Java была разработана для использования UTF-16. Фактически, тип данных char изначально использовался для представления 16-битной кодовой точки Unicode.

Кодировка UTF-8 указана в RFC 2279;

Наборы символов UTF-16 указаны в RFC 2781

Наборы символов UTF-16 используют шестнадцатибитные величины и поэтому чувствительны к порядку байтов. В этих кодировках порядок байтов потока может указываться меткой начального порядка байтов, представленной символом Unicode '\ uFEFF'. Метки порядка байтов обрабатываются следующим образом:

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.

См. также это

person ayush    schedule 20.01.2011
comment
UTF-8 и UTF-16 не являются наборами символов; это две разные кодировки переменной ширины одной и той же кодировки: Unicode. - person tchrist; 20.01.2011

Что ж, когда я использую этот код, я получаю ‹---------------- как должно и 1/2 для \u00BD как должно быть.

http://www.unicode.org/charts/

person masijade    schedule 20.01.2011