咨询:en_US.UTF-8环境下大写UTF-8字符转小写后字节变长实例
直接给结论:在en_US.UTF-8遵循的Unicode默认大小写规则里,找不到单个大写字符转小写后字节变长的实例。接下来我拆解下原因,再结合你遇到的转大写长度超限的问题,给几个实用的替代思路。
为啥大写转小写不会变长?
Unicode的大小写映射设计里,绝大多数「一个字符转多个字符」的情况都是小写转大写的方向——比如你提到的U+0587转大写后变成两个2字节字符,总长度直接翻倍;还有德语的ß(U+00DF,2字节)转大写是SS(虽然字节数没变,但也是单字符转双字符)。
而大写转小写的场景,几乎全是1:1映射:要么是单个字符转成另一个同字节长度的字符(比如Æ(U+00C6,2字节)转成æ(U+00E6,2字节)),要么是转成更短的字节序列(比如带圈的大写Ⓐ(3字节)转成普通小写a(1字节))。
这是因为Unicode对常见的大小写组合都提供了预组合字符:比如带变音符号的大写字符,对应的小写几乎都有现成的预组合等价字符,不需要拆成多个Unicode码点,自然也就不会增加字节长度。
有没有特殊例外?
严格说,如果你强制用**规范分解形式(NFD)**做大小写转换,可能会出现大写转小写后拆成多个码点的情况,但这不是en_US.UTF-8 locale的默认行为——默认情况下,locale的大小写转换会优先返回预组合字符(NFC形式),所以不会出现字节变长的情况。
举个例子:大写的Ḋ(U+1E0A,3字节)转小写,默认会返回预组合的ḋ(U+1E0B,3字节),长度不变;只有你特意要求分解时,才会得到d(1字节)加上面的点(2字节),总字节数还是3,没增加。
针对你的字符串比较问题的建议
既然转大写会碰到长度超限的坑,给你几个更靠谱的方案:
- 用locale支持的UTF-8大小写比较函数:比如GNU系统里的
strcasestr(配合en_US.UTF-8 locale),或者wcscasecmp(先把UTF-8转成宽字符再比较),这些函数不用显式转换字符串,直接在比较时处理大小写不敏感,从根源避免长度膨胀。 - 用ICU库处理:ICU是专门做Unicode国际化的库,里面的
ucol_strcoll可以配置成不区分大小写的比较,完全适配各种UTF-8场景,不用担心长度限制。 - 截断转换后的字符串(慎选):如果非得保留转大写的方案,可以把转换后的字符串截断到255字节,但这可能会破坏字符串完整性,导致比较结果出错,只适合极端场景。
内容的提问来源于stack exchange,提问作者Baker

