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

时间:2017-01-13 14:46:29

标签: java regex internationalization case-folding

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

我认为java.regex.PatternPattern.UNICODE_CASE相结合,我很幸运。 Javadoc说:

  

UNICODE_CASE启用支持Unicode的案例折叠。当指定此标志时   不区分大小写的匹配,当由CASE_INSENSITIVE标志启用时,   以符合Unicode标准的方式完成。

以下代码:

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,这可能是也可能不是案例折叠(也许我在这里混淆概念)。但是,德语区域设置中的其他字符不会“折叠”,例如ü不会变为UE。因此,为了使我的初始示例更加完整,有没有办法让GrüßeGruesse在Java中相等?

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

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

使用当前接受的答案:

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)。

答案 2 :(得分:0)

供参考,以下事实:

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

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

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

结论(正如@VGR所指出的):如果你需要不区分大小写匹配案例折叠,你需要这样做:

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

而不是:

foo.equalsIgnoreCase(bar)

关于üue的平等,我设法用RuleBasedCollator和我自己的规则(人们希望Locale.German建立了这个规则 - 但是,唉)。它看起来非常愚蠢/过度设计,因为我只需要平等,而不是排序/整理,最后我在比较之前找到了一套简单的String.replace。它很糟糕但它有效且透明/可读。