如何解决这个(大概)与编码相关的错误(Java、Gradle)?
How to fix this (presumably) encoding-related error (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:<Шал[ом]>
很明显,这与字节大小有关。
我试图在 minimal project 中重现该问题,其中包含方法和测试。代码是一样的,但是原代码中出现的问题在这个最小项目中没有出现。
我试图找出它们之间的区别,并比较了 minimal 和原始项目中的编码。根据 Notepad++ (UTF-8),它们是相同的。
还有什么可能导致此测试失败?我该如何解决?
注意:我正在使用Java 1.8和Gradle 2.14(由于客户的要求,我无法升级到更新的版本)。
你是对的,字符串的字节大小在很大程度上取决于你使用的从字符串生成字节的编码。当您使用不带参数的 String.getBytes()
时,将使用默认编码。在 *nix 系统上是 UTF-8
,在 Windows 系统上是 `ISO-8859-1'。
你的 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()
这样的方法,或者你总是在不同的 OS 或不同的上下文中有不同的行为。
我有以下方法,它运行将字符串分类为特定大小(以字节为单位):
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:<Шал[ом]>
很明显,这与字节大小有关。
我试图在 minimal project 中重现该问题,其中包含方法和测试。代码是一样的,但是原代码中出现的问题在这个最小项目中没有出现。
我试图找出它们之间的区别,并比较了 minimal 和原始项目中的编码。根据 Notepad++ (UTF-8),它们是相同的。
还有什么可能导致此测试失败?我该如何解决?
注意:我正在使用Java 1.8和Gradle 2.14(由于客户的要求,我无法升级到更新的版本)。
你是对的,字符串的字节大小在很大程度上取决于你使用的从字符串生成字节的编码。当您使用不带参数的 String.getBytes()
时,将使用默认编码。在 *nix 系统上是 UTF-8
,在 Windows 系统上是 `ISO-8859-1'。
你的 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()
这样的方法,或者你总是在不同的 OS 或不同的上下文中有不同的行为。