Java的equalsIgnoreCase有什么正确的替代方法吗?

10

有很多例子说明为什么和何时使用不正确的区域设置会导致java.lang.String.equalsIgnoreCase失败。

但我没有找到任何正确使用方式的示例。与java.lang.String.toUpperCase不同,它没有带有区域设置参数的版本。将两个字符串转换为大写或小写似乎是浪费的,特别是当您正在处理进行许多比较的应用程序时。

考虑到区域设置和性能,正确的方法是什么来进行忽略大小写的字符串比较?


1
也许可以使用 Collator - fge
3
你介意在问题中加入一些使用.equalsIgnoreCase()出现错误结果的示例吗?我很好奇... - fge
@fge,土耳其语中的“i”和德语中的“ß”似乎是最常被引用的失败案例。但你说得对,我稍后会添加一些例子。 - Martin
仍在等待示例 ;) - Vogel612
1
@fge,我知道你的评论已经有一段时间了,但是我刚刚遇到了一个惊人的例子:"\u0130".equalsIgnoreCase("\u0130".toLowerCase())。该代码返回false(OpenJDK 1.8.0_121)。 - Bernie
2个回答

1
根据此页面,您可以使用 Collator 来进行不区分大小写的相等判断,如下所示:
//retrieve the runtime user's locale
Locale locale = new Locale(getUserLocale());

//pass the user's locale as an argument
Collator myCollator = Collator.getInstance(locale);

//set collator to Ignore case but not accents
//(default is Collator.TERTIARY, which is
//case sensitive)
myCollator.setStrength(Collator.SECONDARY);

int i = myCollator.compare(stringA,stringB);

显然,在其他情境下你可能会选择不同的地区设置。


针对 @fge - 这份Oracle Bug报告提供了一个类似于此类问题的示例。

0
一个可能的替代方案是滥用正则表达式。这在动态变化的字符串中会非常消耗性能,但如果你要与常量进行比较,它 可能 是一种替代方案:
Matcher matcher = Pattern.compile("^" + myOtherString + "$",
    Pattern.CASE_INSENSITIVE | Pattern.LITERAL | Pattern.UNICODE_CASE).matcher();
if (matcher.matches(myString)) {
   // ...
}

这个函数锚定了你想要比较的字符串,并指定了对字面字符串进行 Unicode 感知的不区分大小写匹配。


我预测使用String.equalsIgnoreCase会遇到与此相同的问题。比较需要考虑区域设置,而不仅仅是Unicode。(根据String javadocs,String.equalsIgnoreCase也支持Unicode) - Stephen C
@StephenC,这个很酷的部分是,你答案中给出的示例不会有同样的问题。ß -> SS问题源于没有大写等效项ß的事实。只有ß将匹配ß,ss将不会匹配ß(就像equalsIgnoreCase()中发生的那样)。 - Vogel612

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接