Почему ¿ отображается по-разному в Windows и Linux даже при использовании UTF-8?
-
05-07-2019 - |
Вопрос
Почему следующее отображается по-разному в Linux и Windows?
System.out.println(new String("¿".getBytes("UTF-8"), "UTF-8"));
в Windows:
¿
в Linux:
¿
Решение
System.out.println() выводит текст в системной кодировке по умолчанию, но консоль интерпретирует этот вывод в соответствии со своей собственной настройкой кодировки (или «кодовой страницы»).На вашем компьютере с Windows две кодировки, похоже, совпадают, но на компьютере с Linux выходные данные, очевидно, имеют формат UTF-8, а консоль декодирует их как однобайтовую кодировку, например ISO-8859-1.Или, может быть, как предположил Джон, исходный файл сохраняется как UTF-8 и javac
читает его как что-то другое, и этой проблемы можно избежать, используя escape-символы Unicode.
Когда вам нужно вывести что-либо, кроме текста ASCII, лучше всего записать это в файл, используя соответствующую кодировку, а затем прочитать файл с помощью текстового редактора — консоли слишком ограничены и слишком зависят от системы.Кстати, этот кусочек кода:
new String("¿".getBytes("UTF-8"), "UTF-8")
...не влияет на результат.Все, что для этого нужно, — это кодировать содержимое строки в массив байтов и снова декодировать его, воспроизводя исходную строку — дорогостоящая операция, не требующая никаких операций.Если вы хотите вывести текст в определенной кодировке, вам нужно использовать OutputStreamWriter, например:
FileOutputStream fos = new FileOutputStream("out.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
Другие советы
Не знаю, в чем именно проблема, но стоит отметить, что
¿ (0xc2,0xbf)
это результат кодировки UTF-8
0xbf,
который является кодовой точкой Unicode для ¿
Итак, в случае с Linux выходные данные отображаются не как utf-8, а как однобайтовая строка.
Проверьте, какую кодировку имеет ваш Linux-терминал.
Для gnome-терминала в Ubuntu — перейдите в меню «Терминал» и выберите «Установить кодировку символов».
Для putty: Конфигурация -> Окно -> Перевод -> UTF-8 (если это не работает, см. эта почта).
Запустите этот код, чтобы определить, является ли это проблемой компилятора или консоли:
public static void main(String[] args) throws Exception {
String s = "¿";
printHex(Charset.defaultCharset(), s);
Charset utf8 = Charset.forName("UTF-8");
printHex(utf8, s);
}
public static void printHex(Charset encoding, String s)
throws UnsupportedEncodingException {
System.out.print(encoding + "\t" + s + "\t");
byte[] barr = s.getBytes(encoding);
for (int i = 0; i < barr.length; i++) {
int n = barr[i] & 0xFF;
String hex = Integer.toHexString(n);
if (hex.length() == 1) {
System.out.print('0');
}
System.out.print(hex);
}
System.out.println();
}
Если закодированные байты для UTF-8 различны на каждой платформе (это должно быть c2bf), это проблема компилятора.
Если это проблема компилятора, замените «¿» на "\u0000".
Трудно точно узнать, какие байты содержит ваш исходный код или строку, к которой вызывается getBytes(), из-за кодировок вашего редактора и компилятора.
Можете ли вы создать короткую, но полную программу, содержащую только ASCII (и соответствующий экранирующий \uxxxx в строке), которая по-прежнему показывает проблему?
Я подозреваю, что проблема вполне может быть связана с выводом консоли в Windows или Linux, но было бы хорошо сначала получить воспроизводимую программу.