Java 1.6 Windows-1252 кодирование не удается на 3 символа - PullRequest
4 голосов
/ 27 января 2010

РЕДАКТИРОВАТЬ: я был убежден, что этот вопрос несколько бессмысленно. Спасибо тем, кто откликнулся. Я могу опубликовать дополнительный вопрос, более конкретный.

Сегодня я инвестировал некоторые проблемы с кодированием и написал этот модульный тест, чтобы изолировать базовый случай репро:

int badCount = 0;
for (int i = 1; i < 255; i++) {
    String str = "Hi " + new String(new char[] { (char) i });

    String toLatin1  = new String(str.getBytes("UTF-8"), "latin1");
    assertEquals(str, new String(toLatin1.getBytes("latin1"), "UTF-8"));

    String toWin1252 = new String(str.getBytes("UTF-8"), "Windows-1252");
    String fromWin1252 = new String(toWin1252.getBytes("Windows-1252"), "UTF-8");

    if (!str.equals(fromWin1252)) {
        System.out.println("Can't encode: " + i + " - " + str + 
                           " - encodes as: " + fromWin1252);
        badCount++;
    }
}

System.out.println("Bad count: " + badCount);

Выход:

    Can't encode: 129 - Hi ? - encodes as: Hi ??
    Can't encode: 141 - Hi ? - encodes as: Hi ??
    Can't encode: 143 - Hi ? - encodes as: Hi ??
    Can't encode: 144 - Hi ? - encodes as: Hi ??
    Can't encode: 157 - Hi ? - encodes as: Hi ??
    Can't encode: 193 - Hi Á - encodes as: Hi ??
    Can't encode: 205 - Hi Í - encodes as: Hi ??
    Can't encode: 207 - Hi Ï - encodes as: Hi ??
    Can't encode: 208 - Hi ? - encodes as: Hi ??
    Can't encode: 221 - Hi ? - encodes as: Hi ??
    Bad count: 10

JDK 1.6.0_07 в Mac OS 10.6.2

Мое наблюдение:

Latin1 симметрично кодирует все 254 символа. Windows-1252 нет. Три печатных символа (193, 205, 207) - это одинаковые коды в Latin1 и Windows-1252, поэтому я не ожидаю каких-либо проблем.

Может кто-нибудь объяснить это поведение? Это ошибка JDK?

- Джеймс

Ответы [ 2 ]

4 голосов
/ 27 января 2010

По моему мнению, программа тестирования глубоко испорчена, потому что она делает практически бесполезные преобразования между строками без семантического значения.

Если вы хотите проверить, являются ли все байтовые значения действительными значениями для данной кодировки, то что-то вроде этого может быть больше похоже на это:

public static void tryEncoding(final String encoding) throws UnsupportedEncodingException {
    int badCount = 0;
    for (int i = 1; i < 255; i++) {
        byte[] bytes = new byte[] { (byte) i };

        String toString = new String(bytes, encoding);
        byte[] fromString = toString.getBytes(encoding);

        if (!Arrays.equals(bytes, fromString)) {
            System.out.println("Can't encode: " + i + " - in: " + Arrays.toString(bytes) + "/ out: "
                    + Arrays.toString(fromString) + " - result: " + toString);
            badCount++;
        }
    }

    System.out.println("Bad count: " + badCount);
}

Обратите внимание, что эта программа тестирования проверяет входные данные с использованием (usnigned) значений байтов от 1 до 255. Код в вопросе использует значения char (эквивалентные кодовым точкам Unicode в этом диапазон) от 1 до 255.

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

Выполнение этого с "Windows-1252" в качестве аргумента приводит к выводу:

Can't encode: 129 - in: [-127]/ out: [63] - result: �
Can't encode: 141 - in: [-115]/ out: [63] - result: �
Can't encode: 143 - in: [-113]/ out: [63] - result: �
Can't encode: 144 - in: [-112]/ out: [63] - result: �
Can't encode: 157 - in: [-99]/ out: [63] - result: �
Bad count: 5

Что говорит нам о том, что Windows-1252 не принимает значения байтов 129, 1441, 143, 144 и 157 в качестве допустимых значений. (Примечание: здесь я говорю о значениях без знака. Приведенный выше код показывает -127, -115, ... потому что Java знает только байты без знака).

Статья в Википедии о Windows-1252 , кажется, подтверждает это наблюдение, заявляя следующее:

Согласно информации на сайтах Microsoft и Консорциума Unicode, позиции 81, 8D, 8F, 90 и 9D не используются

2 голосов
/ 27 января 2010

То, что делает ваш код (String->byte[]->String, дважды), в значительной степени является противоположным транскодированию и не имеет никакого смысла (практически гарантированно потеря данных).Транскодирование означает byte[]->String->byte[]:

public byte[] transcode(byte[] input, String inputEnc, String targetEnc)
{
    return new String(input, inputEnc).getBytes(targetEnc);
}

И, конечно, он потеряет данные, когда ввод содержит символы, которые целевая кодировка не поддерживает.

...