Unicode编码的四字节字符的判断方法

项目场景:

在MFC静态文本控件上显示一串字符串,用wchar_t数组存储。如果是连续的半角英文字母或者数字,不能自动换行(汉字或字符串中有空格的话也可以自动换行),后面的字符会被隐藏掉。为了让显示的字符串都能根据文本控件的长度而自动换行,根据控件的长度在字符串的适当位置添加换行符,实现字符串的自动换行。

在这里插入图片描述


问题描述

字符串中有四字节字符的时候,字符有可能显示异常


原因分析:

在Windows系统下,wchar_t采用UTF-16编码。对于英文和大部分中文,它们通常占用2个字节,用于存储Unicode编码的字符。然而,对于某些特殊的字符,它们可能需要占用4个字节(比如𩸽),需要2个wchar_t来存储。

所以如果字符串中有四字节字符的时候,按上述方法,有可能在存储4字节的2个wchar_t中间添加换行符,导致这个字符显示异常。

验证

俩个一样大小的文本控件,左边的控件一行正常可以显示8个汉字。更改显示到右边控件的字符串,在第存储第8个汉字的俩个wchar_t中间,添加换行符。结果和猜想一致,第8个汉字显示异常。

wchar_t wchLeftText[100];
memset(wchLeftText, 0, sizeof(wchLeftText));

wchar_t wchRightText[120];
memset(wchRightText, 0, sizeof(wchRightText));

wsprintf(wchLeftText, L"%s", L"𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽𩸽");

int iTemp = 0;
for (int i = 0; i < 100; i++)
{
	wchRightText[iTemp] = wchLeftText[i];
	iTemp++;
	if (i == 14)
	{
		wchRightText[iTemp] = '\n';
		iTemp++;
	}
}
GetDlgItem(IDC_STATIC)->SetWindowText(wchLeftText);
GetDlgItem(IDC_STATIC1)->SetWindowText(wchRightText);

在这里插入图片描述


解决方案:

判断每个wchar_t存储的内容是2字节字符还是4字节字符,如果是4字节字符,换行符不能添加在4字节字符中间。

4字节字符的判断方法
字符的前16位范围是0xD800~0xDBFF

int utf16CodePoint = (int)wchar_t[x]
if (utf16CodePoint >= 0xD800 && utf16CodePoint <= 0xDBFF)
{
    // 4字节
}

[参考]

UTF-16是一种用于表示Unicode字符的编码方式,它使用16位(2字节)来表示一个字符。而UCS-2则是一种更早的字符编码方式,它使用16位(2字节)来表示一个字符,但只能表示BMP(Basic
Multilingual Plane,基本多语言平面)中的字符。

为了向后兼容UCS-2,UTF-16使用了一种称为surrogate pair的机制。Surrogate
pair由两个相邻的字符组成,一个称为high surrogate(高代理),另一个称为low
surrogate(低代理)。它们一起表示一个超出BMP范围的字符。

具体来说,高代理的范围是0xD800到0xDBFF,而低代理的范围是0xDC00到0xDFFF。每个高代理都与一个低代理配对,共同表示一个4字节的字符。这样做的目的是为了将UCS-2中的字符映射到UTF-16中,以便在保持向后兼容的同时,能够表示更多的字符。

通过使用surrogate
pair,UTF-16能够表示的字符范围是0x000000到0x10FFFF,这与UCS-2中的字符范围相同。然而,UTF-16能够表示的字符数量实际上超过了UCS-2的范围。这是因为UCS-2只能表示2字节(16位)的字符,而UTF-16可以使用最多4字节(32位)来表示一个字符。

总之,surrogate
pair是一种用于UTF-16编码中表示超出BMP范围的字符的机制。它通过将高代理和低代理配对起来,共同表示一个4字节的字符,实现了UTF-16对UCS-2的向后兼容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值