Swift中如何初始化超出UInt16范围的UniChar变量?
解决UniChar无法存储大Unicode值的问题
这个问题其实是UTF-16编码的典型坑——咱们先把本质说清楚:UniChar本质就是UInt16,也就是16位无符号整数,它的取值范围仅限0到65535(对应Unicode的U+0000到U+FFFF,也就是基本多语言平面BMP)。你用的128701对应的是Unicode补充平面的字符U+1F97D(🥽),这类字符的码点超过了16位上限,单个UniChar根本装不下,必须用UTF-16代理对(两个连续的UniChar)来表示。
下面给你几个实用的解决方法:
1. 直接用代理对数值初始化数组
每个补充平面字符都对应一对固定的代理值,你可以直接把这两个值存在UniChar数组里。比如U+1F97D对应的代理对是U+D83E(十进制55358)和U+DD7D(十进制56693):
// 用十六进制更直观 UniChar mySurrogatePair[] = {0xD83E, 0xDD7D}; // 或者用十进制 UniChar mySurrogatePair[] = {55358, 56693};
2. 通过NSString自动转换(最省心)
如果你已经有目标字符的字符串,直接让系统帮你处理代理对转换就好,不用自己查数值:
NSString *targetStr = @"🥽"; NSUInteger strLength = [targetStr length]; // 这里返回2,因为是代理对 UniChar *charBuffer = malloc(sizeof(UniChar) * strLength); [targetStr getCharacters:charBuffer range:NSMakeRange(0, strLength)]; // 现在charBuffer里就是两个UniChar值:0xD83E和0xDD7D // 使用完记得释放内存 free(charBuffer);
这里要注意,NSString的length方法返回的是UTF-16编码的长度,补充平面字符会占用2个长度单位,正好对应两个UniChar。
3. 手动计算代理对(适合动态生成的场景)
如果你手里只有十进制/十六进制的Unicode码点,也可以通过公式手动算出代理对:
- 先把码点减去
0x10000,得到一个20位的数值(因为补充平面的码点范围是U+10000到U+10FFFF,减去0x10000后正好是0到0xFFFFF,20位) - 取这个数值的高10位,加上
0xD800得到高代理字符(第一个UniChar) - 取低10位,加上
0xDC00得到低代理字符(第二个UniChar)
比如对U+1F97D(十进制128701)的计算:
uint32_t codePoint = 0x1F97D; // 或者直接写128701 uint32_t offset = codePoint - 0x10000; UniChar highSurrogate = 0xD800 + (offset >> 10); UniChar lowSurrogate = 0xDC00 + (offset & 0x3FF); // 最终highSurrogate=0xD83E,lowSurrogate=0xDD7D
最后提醒
- 单个
UniChar只能存BMP范围内的字符,超出范围的必须用代理对,不要试图把大码点硬塞给单个UniChar,那肯定会溢出。 - 代理对里的两个字符是绑定的,单独使用其中一个会显示乱码,处理时要把它们当成一个整体。
内容的提问来源于stack exchange,提问作者johnnietheblack
相关产品推荐
相关产品推荐

