【问题标题】:Case insensitive comparisons across locales in JavaJava 中跨语言环境的不区分大小写比较
【发布时间】:2023-03-24 03:30:02
【问题描述】:

考虑下面的Java代码比较一个包含German grapheme ß的小字符串

String a = "ß";
String b = a.toUpperCase();

assertTrue(a.equalsIgnoreCase(b));

比较失败,因为 "ß".toUpperCase() 实际上等于 "SS",这最终导致在 equalsIgnoreCase() 中的检查失败。 toUpperCase() 的 Javadocs 确实明确提到了这个案例,但是我不明白为什么这没有转到 ẞ, the capital variant of ß

更一般地说,我们应该如何进行不区分大小写的比较,可能跨越不同的语言环境。我们是否应该始终使用toUpper()equalsIgnoreCase(),而不是两者都使用?

似乎问题在于equalsIgnoreCase()的实现包括以下检查:anotherString.value.length == value.length,这似乎与toUpper()Javadocs不兼容,其中状态:

由于大小写映射并不总是 1:1 字符映射,因此生成的 字符串的长度可能与原始字符串不同。

【问题讨论】:

标签: java localization linguistics


【解决方案1】:

Java 的Collator 类专为不同区域敏感的文本比较操作而设计。由于“大写”的概念在不同语言环境之间存在很大差异,Collator 使用了一个更细粒度的模型,称为比较strength。提供了四个级别,它们如何影响比较取决于区域设置。

这是一个使用 Collator 和德语区域设置的示例,用于对字母 ß 进行不区分大小写的比较:

Collator germanCollator = Collator.getInstance(Locale.GERMAN);
int[] strengths = new int[] {Collator.PRIMARY, Collator.SECONDARY,
                             Collator.TERTIARY, Collator.IDENTICAL};

String a = "ß";
String b = "ß".toUpperCase();

for (int strength : strengths) {
    germanCollator.setStrength(strength);
    if (germanCollator.compare(a, b) == 0) {
        System.out.println(String.format(
                "%s and %s are equivalent when comparing differences with "
                + "strength %s using the GERMAN locale.",
                a, b, String.valueOf(strength)));
    }
}

代码打印出来

ß 和 SS 在使用 GERMAN 语言环境比较强度为 0 的差异时是等价的。 ß 和 SS 在使用德语语言环境比较强度 1 的差异时是等价的。

这意味着德语语言环境在PRIMARYSECONDARY 强度比较中认为这两个字符串相等。

【讨论】:

    最近更新 更多