无论是在字符串上还是在字符上,您实际上都不能完全正确地完成这项工作。toLowerCase
问题是大写或小写都有变体字形,并且取决于您是大写还是小写,您的字形可能会或可能不会被保留。当您说忽略大小写比较小写字形的两个变体时,甚至不清楚您的意思是:它们是相同的还是不相同的?(请注意,也有混合大小写的字形:\u01c5, \u01c8, \u01cb, \u01f2
或Dž、Lj、Nj、Dz,但此处建议的任何方法都适用于这些字形,只要它们应该与它们的完全大写或完全小写变体相同。)
使用还有一个额外的问题Char
:有大约 80 个代码点无法用一个Char
大写/小写变体(每个 40 个)表示,至少由 Java 的代码点大写/小写检测到。因此,您需要获取代码点并更改它们的大小写。
但是代码点对变体字形没有帮助。
无论如何,这里有一个完整的由于变体而有问题的字形列表,展示了它们在 6 种变体方法中的表现:
- 特点
toLowerCase
- 特点
toUpperCase
- 细绳
toLowerCase
- 细绳
toUpperCase
- 细绳
equalsIgnoreCase
- 字符
toLowerCase(toUpperCase)
(反之亦然)
对于这些方法,S
意味着变体被视为彼此相同,D
意味着变体被视为彼此不同。
Behavior Unicode Glyphs
=========== ================================== =========
1 2 3 4 5 6 Upper Lower Var Up Var Lo Vr Lo2 U L u l l2
- - - - - - ------ ------ ------ ------ ------ - - - - -
D D D D S S \u0049 \u0069 \u0130 \u0131 I i İ ı
S D S D S S \u004b \u006b \u212a K k K
D S D S S S \u0053 \u0073 \u017f S s ſ
D S D S S S \u039c \u03bc \u00b5 Μ μ µ
S D S D S S \u00c5 \u00e5 \u212b Å å Å
D S D S S S \u0399 \u03b9 \u0345 \u1fbe Ι ι ͅ ι
D S D S S S \u0392 \u03b2 \u03d0 Β β ϐ
D S D S S S \u0395 \u03b5 \u03f5 Ε ε ϵ
D D D D S S \u0398 \u03b8 \u03f4 \u03d1 Θ θ ϴ ϑ
D S D S S S \u039a \u03ba \u03f0 Κ κ ϰ
D S D S S S \u03a0 \u03c0 \u03d6 Π π ϖ
D S D S S S \u03a1 \u03c1 \u03f1 Ρ ρ ϱ
D S D S S S \u03a3 \u03c3 \u03c2 Σ σ ς
D S D S S S \u03a6 \u03c6 \u03d5 Φ φ ϕ
S D S D S S \u03a9 \u03c9 \u2126 Ω ω Ω
D S D S S S \u1e60 \u1e61 \u1e9b Ṡ ṡ ẛ
更复杂的是,除非您知道自己使用的是土耳其语,否则无法让土耳其语 I 是正确的(即带点的版本与不带点的版本不同)。这些方法都不能提供正确的行为,除非您知道语言环境(即非土耳其语:i
并且I
是相同的忽略大小写;土耳其语,不是)。
总体而言, usingtoUpperCase
为您提供了最接近的近似值,因为您只有五个大写变体(或四个,不包括土耳其语)。
你也可以尝试专门拦截这五个麻烦的案例,toUpperCase(toLowerCase(c))
单独调用。如果你仔细选择你的守卫(toUpperCase
如果c < 0x130 || c > 0x212B
,然后通过其他替代方案),你只能在低范围内的字符上获得约 20% 的速度损失(相比之下,如果你将单个字符转换为字符串和equalsIgnoreCase
它们,则为约 4 倍)和如果您在危险区域中有很多东西,则只有大约 2 倍的惩罚。你仍然有 dotted 的语言环境问题I
,但除此之外你的状态还不错。当然,如果你可以equalsIgnoreCase
在更大的字符串上使用,你最好这样做。
这是完成这项工作的示例 Scala 代码:
def elevateCase(c: Char): Char = {
if (c < 0x130 || c > 0x212B) Character.toUpperCase(c)
else if (c == 0x130 || c == 0x3F4 || c == 0x2126 || c >= 0x212A)
Character.toUpperCase(Character.toLowerCase(c))
else Character.toUpperCase(c)
}