(Untitled)
我在MSYS2下做了测试。Emoji字符📁需要2个wchar_t
,需要4个char
。Emoji字符✏️则需要2个wchar_t
,需要6个char
。
Emoji | Platform | wchar_t |
char |
Display | mbrtowc | pwccheck |
---|---|---|---|---|---|---|
📁 | MSYS2 | 2 | 4 | ❌ | 3→1 | ❌ |
✏️ | MSYS2 | 2 | 6 | ✔️ | 3→1 | ✔️ |
❌ | MSYS2 | 1 | 3 | ✔️ | 3→1 | ✔️ |
📁 | CentOS | 1 | 4 | ✔️ | 4→1 | ✔️ |
✏️ | CentOS | 2 | 6 | ✔️ | 3→1 | ✔️ |
❌ | CentOS | 1 | 3 | ✔️ | 3→1 | ✔️ |
我们将这个表格归纳一下,由于转换过程是从小到大逐步尝试的,于是我们会遇到这个情况:将一个3字符长度的字符串尝试转换为一个宽字符后,它位于了代理项代码点(surrogate code point),是一个代理项代码单元。
这里有几个概念需要介绍一下(回答来自必应AI)。
A surrogate code point is a Unicode code point in the range U+D800…U+DFFF1. It is reserved for use by UTF-16, where a pair of surrogate code units (a high surrogate followed by a low surrogate) “stand in” for a supplementary character21.
一个代理项代码点是在范围 U+D800…U+DFFF1 的 Unicode 代码点。它被 UTF-16 保留,用于一对代理项代码单元(一个高代理项后跟一个低代理项)来“代替”一个补充字符。
一个例子是,Unicode 代码点 U+1F339(🌹)是一个补充字符,它在 UTF-16 中被编码为两个代理项代码单元:0xD83C(高代理项)和 0xDF39(低代理项)。
🌹 用 UTF-8 表示是 0xF0 0x9F 0x8C 0xB91。UTF-8 是一种变长字符编码,被定义为将码点编码为 1 至 4 个字节,具体取决于码点数值中有效二进制位的数量。
Unicode 的补充字符是指分配了 U+10000 到 U+10FFFF1 的 Unicode 代码点。在 UTF-8 中,这些字符都是 4 个字节长的1。所以,没有长度大于 4 的 Unicode 补充字符。
代理项代码单元与补充字符的关系是这样的:补充字符是指位于基本多文种平面(BMP)之外的字符,而代理项是 UTF-16 代码值1。在 UTF-16 中,需要一对代理项(一个高代理项和一个低代理项)来表示一个补充字符12。高代理项的范围是 U+D800 到 U+DBFF,低代理项的范围是 U+DC00 到 U+DFFF13。
所以这里有一个问题,mbrtowc
函数转换了一个Unicode补充字符的前三个字符串,得到了一个宽字符串,是这个补充字符代理项对的前导代码单元,导致还剩下的一个字符肯定无法转换为正确的数据了。
根据必应提供的背景知识,补充字符一定是4个字符组成的。因此此处应该将4个字符一起处理,将其转换为2个宽字符。
这或许是mbrtowc在MSYS2下的问题,可能是因为Windows下的wchar_t的长度是2。
由于转换过程是4个字符串转换为2个宽字符串,故我们需要使用mbstowcs系列函数。