Кодировка символов UTF-8 в Java

У меня возникают некоторые проблемы с получением некоторого французского текста для преобразования в UTF8, чтобы он отображался правильно, либо в консоли, либо в текстовом файле, либо в элементе GUI.

Исходная строка

HANDICAP╔ES

который должен быть

HANDICAPÉES

Вот фрагмент кода, который показывает, как я использую jackcess Драйвер базы данных для чтения в файле Access Acccess в Eclipse/Linux.

Database database = Database.open(new File(filepath));
Table table = database.getTable(tableName, true);
Iterator rowIter = table.iterator();
while (rowIter.hasNext()) {
    Map<String, Object> row = this.rowIter.next();
    // convert fields to UTF
    Map<String, Object> rowUTF = new HashMap<String, Object>();
    try {
        for (String key : row.keySet()) {
            Object o = row.get(key);
            if (o != null) {
                String valueCP850 = o.toString();
                // String nameUTF8 = new String(valueCP850.getBytes("CP850"), "UTF8"); // does not work!
                String valueISO = new String(valueCP850.getBytes("CP850"), "ISO-8859-1");
                String valueUTF8 = new String(valueISO.getBytes(), "UTF-8"); // works!
                rowUTF.put(key, valueUTF8);
            }
        }
    } catch (UnsupportedEncodingException e) {
        System.err.println("Encoding exception: " + e);
    }   
}

В коде вы увидите, где я хочу конвертировать непосредственно в UTF8, который, похоже, не работает, поэтому мне нужно сделать двойное преобразование. Также обратите внимание, что, как представляется, не существует способа указать тип кодировки при использовании драйвера входов.

Спасибо, Cam

Ответ 1

Новый анализ, основанный на новой информации.
Похоже, ваша проблема связана с кодировкой текста, прежде чем он будет сохранен в базе данных доступа. Кажется, он был закодирован как ISO-8859-1 или windows-1252, но декодирован как cp850, в результате чего строка HANDICAP╔ES хранится в БД.

Правильно извлекая эту строку из БД, вы теперь пытаетесь изменить исходную ошибку кодирования и восстановить строку, как и должно было быть сохранено: HANDICAPÉES. И вы выполняете это с помощью этой строки:

String valueISO = new String(valueCP850.getBytes("CP850"), "ISO-8859-1");

getBytes("CP850") преобразует символ в значение байта 0xC9, а конструктор String декодирует его согласно ISO-8859-1, в результате чего появляется символ É. Следующая строка:

String valueUTF8 = new String(valueISO.getBytes(), "UTF-8");

... ничего не делает. getBytes() кодирует строку в кодировке по умолчанию платформы, которая является UTF-8 в вашей системе Linux. Затем конструктор String декодирует его с той же кодировкой. Удалите эту строку, и вы все равно получите тот же результат.

Более того, ваша попытка создать строку "UTF-8" была ошибочной. Вам не нужно заботиться о кодировании строк Java - они всегда UTF-16. При вводе текста в Java-приложение вам просто нужно убедиться, что вы декодируете его с помощью правильной кодировки.

И если мой анализ верен, ваш драйвер Access правильно декодирует его; проблема находится на другом конце, возможно, до того, как БД даже войдет в картину. Это то, что вам нужно исправить, потому что этот new String(getBytes()) хак не может рассчитывать на работу во всех случаях.


Исходный анализ, основанный на отсутствии информации.: -/
Если вы видите HANDICAP╔ES на консоли, нет проблем. С учетом этого кода:

System.out.println("HANDICAPÉES");

JVM преобразует строку (Unicode) в кодировку по умолчанию платформы, windows-1252, перед ее отправкой на консоль. Затем консоль декодирует, используя свою собственную кодировку по умолчанию, которая, как оказалось, является cp850. Таким образом, консоль отображает это неправильно, но это нормально. Если вы хотите, чтобы он отображался правильно, вы можете изменить консольное кодирование с помощью этой команды:

CHCP 1252

Чтобы отобразить строку в элементе GUI, например JLabel, вам не нужно ничего особенного делать. Просто убедитесь, что вы используете шрифт, который может отображать все символы, но это не должно быть проблемой для французского языка.

Что касается записи в файл, просто укажите нужную кодировку при создании Writer:

OutputStreamWriter osw = new OutputStreamWriter(
    new FileOutputStream("myFile.txt"), "UTF-8");

Ответ 2

String s = "HANDICAP╔ES";
System.out.println(new String(s.getBytes("CP850"), "ISO-8859-1")); // HANDICAPÉES

Это показывает правильное строковое значение. Это означает, что он был первоначально закодирован/декодирован с помощью ISO-8859-1, а затем неправильно закодирован с помощью CP850 (изначально CP1252, так как Windows ANSI, как указано в комментарии, действительно также возможна, поскольку É имеет тот же код, что и в ISO-8859-1).

Совместите среду и бинарные конвейеры, чтобы использовать все одно и то же кодирование символов. Вы не можете и не должны конвертировать между ними. Вы рискуете потерять информацию в диапазоне ASCII таким образом.

Примечание. НЕ используйте приведенный выше фрагмент кода для "исправления" проблемы! Это не будет правильным решением.


Обновить: вы, по-видимому, все еще боретесь с проблемой. Я повторю важные части ответа:

  • Совместите среду и двоичные конвейеры с тем, чтобы использовать all одну и ту же кодировку символов.

  • Вы можете не и не конвертировать между ними. Вы рискуете потерять информацию в диапазоне ASCII таким образом.

  • Используйте НЕ, используя приведенный выше фрагмент кода, чтобы "исправить" проблему! Это не будет правильным решением.

Чтобы устранить проблему, вам нужно выбрать кодировку символов X, которую вы хотите использовать во всем приложении. Я предлагаю UTF-8. Обновление MS Access для использования кодирования X. Обновление среды разработки для использования кодирования X. Обновите читатели и писатели java.io в коде, чтобы использовать кодировку X. Обновляйте редактор для чтения/записи файлов с кодировкой X. Обновите пользовательский интерфейс приложения использовать кодировку X. Do not использовать Y или Z или что-то еще на каком-то шаге. Если символы уже повреждены в каком-то хранилище данных (MS Access, файлы и т.д.), Вам необходимо исправить это, вручную заменив символы прямо там, в хранилище данных. Не используйте Java для этого.

Если вы действительно используете "командную строку" в качестве пользовательского интерфейса, то вы фактически потеряны. Он не поддерживает UTF-8. Как было предложено в комментариях и в статье, связанной с комментариями, вам нужно создать приложение Swing вместо того, чтобы полагаться на ограниченную команду оперативная среда.

Ответ 3

Вы можете указать кодировку при установлении соединения. Этот способ был идеальным и решить мою проблему кодирования:

    DatabaseImpl open = DatabaseImpl.open(new File("main.mdb"), true, null, Database.DEFAULT_AUTO_SYNC, java.nio.charset.Charset.availableCharsets().get("windows-1251"), null, null);
    Table table = open.getTable("FolderInfo");

Ответ 4

Использование " ISO-8859-1" помогло мне разобраться с французскими характеристиками.