Java 中的跨语言环境比较不区分大小写

Case insensitive comparisons across locales in Java

考虑以下 Java 代码比较包含 German grapheme ß

的小字符串
String a = "ß";
String b = a.toUpperCase();

assertTrue(a.equalsIgnoreCase(b));

比较失败,因为“ß”.toUpperCase() 实际上等于 "SS",最终无法在 equalsIgnoreCase() 中进行检查。 toUpperCase() 的 Java 文档确实明确提到了这种情况,但是我不明白为什么这不会转到 ẞ,the capital variant of ß?

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

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

Since case mappings are not always 1:1 char mappings, the resulting String may be a different length than the original String.

Java的Collatorclass是为不同语言环境敏感的文本比较操作而设计的。由于 "upper-case" 的概念在语言环境之间差异很大,因此 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)));
    }
}

代码打印出来

ß and SS are equivalent when comparing differences with strength 0 using the GERMAN locale.
ß and SS are equivalent when comparing differences with strength 1 using the GERMAN locale.

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