使用toLowerCase
,无论是在字符串还是在字符中,都不能完全正确地执行作业。问题在于,在任一大小写字母中都存在变体字形,并且根据您大写或小写字形的方式,可能会保留或不保留这些字形。甚至当您说忽略大小写比较两个小写字母的两个变体时,您所指的含义也不清楚:它们是否相同?(请注意,还有混合大小写的字形:\u01c5、\u01c8、\u01cb、\u01f2
或Dž、Lj、Nj、Dz,但只要将它们视为与其完全大写或完全小写的变体相同,此处建议的任何方法都可以解决它们。)
使用Char
还存在另一个问题:有大约80个代码点用单个Char
无法表示,并且它们是大/小写变体(40个变体)。至少Java的代码点大小写检测到了这些。因此,您需要获取代码点并更改这些代码点的大小写。
但代码点对于变体字形没有帮助。
无论如何,这里是由于变体而出现问题的字形的完整列表,显示它们针对6种变体方法的表现:
- Character
toLowerCase
- Character
toUpperCase
- String
toLowerCase
- String
toUpperCase
- String
equalsIgnoreCase
- Character
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忽略大小写相同;土耳其不同)。
总体而言,使用 toUpperCase 给出了最接近的近似值,因为您只有五个大写变量(或者四个,不包括土耳其)。
您也可以尝试特别拦截这五个棘手的情况,并仅对它们调用 toUpperCase(toLowerCase(c))。如果您仔细选择保护程序(如果 c < 0x130 || c > 0x212B,则只需 toUpperCase,然后通过其他替代方案进行工作),则对于低范围内的字符,只会产生约20%的速度损失(与将单个字符转换为字符串并equalsIgnoreCase它们相比,损失4倍),如果危险区域有很多,只会产生约2倍的损失。除了带点的 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)
}
Character.toLowerCase
或Character.toUpperCase
将所有字符转换为小写或大写并进行比较。 - idiottiger