Как исправить эту (предположительно) ошибку, связанную с кодировкой (Java, Gradle)?

У меня есть следующий метод, который усекает строку до определенного размера в байтах:

public class Utils {
    public static String trimStringToBytesSize(String s, int length) {
        if (s == null || length < 0) return null;
        int trimLength = Math.min(length, s.length());
        String trimmedString = s;
        while (trimmedString.getBytes().length > length && trimLength >= 0) {
            trimmedString = s.substring(0, trimLength);
            trimLength--;
        }
        return trimmedString;
    }
}

Я написал несколько тестов для этого:

@Test
public void trimStringToBytesSize() {
[...]
    trimStringToBytesSizeTestLogic("Шалом",
            6,
            "Шал"
    );
[...]
}

private void trimStringToBytesSizeTestLogic(final String input, final int
        stringLength, final String expectedResult) {
    final String actRes = Utils.trimStringToBytesSize(input, stringLength);
    Assert.assertEquals(expectedResult, actRes);
}

Этот тест прекрасно работает в IntelliJ Idea. Тем не менее, это не удается, когда я запускаю его в Gradle. Ошибка заключается в следующем:

org.junit.ComparisonFailure: expected:<Шал[]> but was:<Шал[ом]>

Очевидно, это связано с размерами байтов.

Я попытался воспроизвести проблему в минимальном проекте, который содержит метод и тест. Код такой же, но проблема, которая появляется в исходном коде, не появляется в этом минимальном проекте.

Я попытался выяснить разницу между ними и сравнил кодировки в минимальном и оригинальном проекте. То же самое в соответствии с Notepad++ (UTF-8).

Что еще может вызвать этот провал теста? Как я могу это исправить?

Примечания: Я использую Java 1.8 и Gradle 2.14 (я не могу перейти на более свежую версию из-за требований заказчика).

1 ответ

Решение

Вы правы, размер байта строки сильно зависит от кодировки, которую вы используете для генерации байтов из строки. Как вы используете String.getBytes() без параметра используется кодировка по умолчанию. Это UTF-8 в системах *nix и `ISO-8859-1'в системах Windows.

Ваша строка Шалом в UTF-8 байты [-48, -88, -48, -80, -48, -69, -48, -66, -48, -68],
Ваша строка Шалом в ISO-8859-1 байты [63, 63, 63, 63, 63] который эффективно ?????потому что ваши символы не могут быть закодированы в ISO-8859-1,

Поэтому, когда ваш тест пройден успешно, у вас есть UTF-8 как кодирование, если он не работает, у вас есть ISO-8859-1 как кодирование, где есть только 5 байтов и, следовательно, строка не затрагивается.

Вы почти никогда не должны использовать такие методы, как String getBytes() или же new String() без указания явной кодировки, или вы всегда ведете себя по-разному в разных ОС или в разных контекстах.

Другие вопросы по тегам