带有 Unicode 的正则表达式模式不进行大小写折叠
Regex Pattern with Unicode doesn't do case folding
在 C# 中,Grüsse
和 Grüße
在大多数情况下被认为是相等的,正如 this 不错的网页所解释的那样。我试图在 Java 中找到类似的行为 - 显然不在 java.lang.String
.
中
我认为 java.regex.Pattern
与 Pattern.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üße
和 Gruesse
在 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üsse
和GRÜẞE
;或 Grüße
和 GRÜẞ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)。
在 C# 中,Grüsse
和 Grüße
在大多数情况下被认为是相等的,正如 this 不错的网页所解释的那样。我试图在 Java 中找到类似的行为 - 显然不在 java.lang.String
.
我认为 java.regex.Pattern
与 Pattern.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üße
和 Gruesse
在 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üsse
和GRÜẞE
;或 Grüße
和 GRÜẞ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)。