на главную обучение сертификация статьи литература ссылки гостевая книга
  Список статей Оглавление Текст статьи  

Java: Русские буквы и не только...

Автор:Астахов Сергей
Создан:03.06.2003


17. Типичные ошибки, или "куда делась буква Ш?"

Буква Ш

   Этот вопрос ("куда делась буква Ш?") довольно часто возникает у начинающих программистов на Java. Давайте разберёмся, куда же она действительно чаще всего девается. :-)

Вот типичная программа а-ля HelloWorld:
  public class Test {
    public static void main(String[] args) {
      System.out.println("ЙЦУКЕНГШЩЗХЪ");
    }
  }
в Far-е сохраняем данный код в файл Test.java, компиляем...
  C:\>javac Test.java
и запускаем...
  C:\>java Test
  ЙЦУКЕНГ?ЩЗХЪ
   Что же произошло? Куда делась буква Ш? Весь фокус здесь в том, что произошла взаимокомпенсация двух ошибок. Текстовый редактор в Far по умолчанию создаёт файл в DOS-кодировке (Cp866). Компилятор же javac для чтения исходника использует file.encoding (если не указано иное ключиком -encoding). А в среде Windows с русскими региональными настройками кодировкой по умолчанию является Cp1251. Это первая ошибка. В результате, в скомпилированном файле Test.class символы имеют неверные кода. Вторая ошибка состоит в том, что для вывода используется стандартный PrintStream, который тоже использует настройку из file.encoding, однако консольное окно в Windows отображает символы, используя кодировку DOS. Если бы кодировка Cp1251 была взаимоодназначной, то потери данных бы не было. Но символ "Ш" в Cp866 имеет код 152, который в Cp1251 не определён, и поэтому отображается на Unicode-символ 0xFFFD. Когда происходит обратное преобразование из char в byte, вместо него подставляется символ "?".

   На аналогичную компенсацию можно нарваться, если прочитать символы из текстового файла при помощи java.io.FileReader, а затем вывести их на экран через System.out.println(). Если файл был записан в кодировке Cp866, то вывод будет идти верно, за исключением опять же буквы Ш.

Прямая конверсия byte<=>char

   Эта ошибка является любимой у зарубежных программистов на Java. Она довольно подробно рассмотрена в начале описания. Если Вы когда-нибудь будете смотреть чужие исходники, то всегда обращайте внимание на явную конверсию типов - (byte) или (char). Довольно часто в таких местах закопаны грабли.

Алгоритм поиска проблем с русскими буквами

   Если Вы не представляете себе где в Вашей программе может происходить потеря русских букв, то можно попробовать следующий тест. Любую программу можно рассматривать как обработчик входных данных. Русские буквы - это такие же данные, они проходят в общем случае три стадии обработки: они откуда-то читаются в память программы (вход), обрабатываются внутри программы и выводятся пользователю (выход). Для того, чтобы определить место проблем, надо попробовать вместо данных зашить в исходник такую тестовую строку: "АБВ\u0410\u0411\u0412", и попробовать её вывести. После этого смотрите, что у Вас вывелось:
  • Если Вы увидите "АБВАБВ", значит компиляция исходников и вывод у Вас работают правильно.

  • Если Вы увидите "???АБВ" (или любые другие символы кроме "АБВ" на месте первых трёх букв), значит вывод работает правильно, но вот компиляция исходников происходит неверно - скорей всего не указан ключик -encoding.

  • Если Вы увидите "??????" (или любые другие символы кроме "АБВ" на месте второй тройки букв), значит вывод у Вас работает неверно.
   Настроив вывод и компиляцию уже можно легко разобраться и со входом. После настройки всей цепочки проблемы должны исчезнуть.


назад оглавление дальше