带有 Unicode 的正则表达式模式不进行大小写折叠

Regex Pattern with Unicode doesn't do case folding

在 C# 中,GrüsseGrüße 在大多数情况下被认为是相等的,正如 this 不错的网页所解释的那样。我试图在 Java 中找到类似的行为 - 显然不在 java.lang.String.

我认为 java.regex.PatternPattern.UNICODE_CASE 的组合很幸运。 Java文档说:

UNICODE_CASE enables Unicode-aware case folding. When this flag is specified then case-insensitive matching, when enabled by the CASE_INSENSITIVE flag, is done in a manner consistent with the Unicode Standard.

还有以下代码:

Pattern p = Pattern.compile(Pattern.quote("Grüsse"), 
                     Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
System.out.println(p.matcher("Grüße").matches());

产量 false。为什么?是否有重现 C# 大小写折叠行为的替代方法?

---- 编辑----

正如@VGR 指出的那样,String.toUpperCase 会将 ß 转换为 ss,这可能是也可能不是大小写折叠(也许我在这里混淆了概念)。然而,德语语言环境中的其他字符不是 "folded",例如 ü 不会变成 UE。所以为了让我的初始示例更完整,有没有办法让 GrüßeGruesse 在 Java 中比较相等?

我在想 java.text.Normalizer class 可以用来做到这一点,但它将 ü 转换为 u? 而不是 ue。它也没有提供 Locale 的选项,这让我更加困惑。

使用 ICU4J 正则表达式,而不是 JDK: http://userguide.icu-project.org/strings/regexp#TOC-Case-Insensitive-Matching

供参考,以下事实:

  • Character.toUpperCase()不能进行大小写折叠,作为一个字符 必须映射到一个字符。

  • String.toUpperCase() 将进行大小写折叠。

  • String.equalsIgnoreCase() 使用 Character.toUpperCase() 在内部,所以不进行大小写折叠。

结论(正如@VGR 指出的):如果你需要不区分大小写的大小写匹配,你需要做:

foo.toUpperCase().equals(bar.toUpperCase())

而不是:

foo.equalsIgnoreCase(bar)

至于 üue 相等,我已经设法用 RuleBasedCollator 和我自己的规则来做到这一点(人们会期望 Locale.German 有那个built-in 但唉)。它看起来真的 silly/over-engineered,因为我只需要相等性,而不是 sorting/collating,最后我在比较之前选择了一组简单的 String.replace。它很糟糕,但它有效并且是 transparent/readable.

当前接受的答案:

foo.toUpperCase().equals(bar.toUpperCase())

以下输入比较相等,即使它们应该相等:GrüsseGRÜẞE;或 GrüßeGRÜẞE.

这是为什么?让我们看看大写的字符串:

"Grüsse".toUpperCase(Locale.ROOT)  -> "GRÜSSE"
"Grüße".toUpperCase(Locale.ROOT)   -> "GRÜSSE"
"GRÜẞE".toUpperCase(Locale.ROOT)   -> "GRÜẞE"

如您所见,大写的“升号 S”() 保持不变。要正确处理该问题,请执行以下操作:

foo.toLowerCase(Locale.ROOT).toUpperCase(Locale.ROOT).equals(
    bar.toLowerCase(Locale.ROOT).toUpperCase(Locale.ROOT))

请注意顺序很重要。如果先大写再小写,它只会将 变成 ß(小写升号 S)。