基于UTF8字符串检查错误替换功能

utf8的长度为1~4个字节,是一种变长串,在转换和传送过程中,可能由于某种意外会导致串出现错误的字符,致使有些工具无法识别而出现乱码,或者直接导致操作无法完成。

实际应用中的例子:游戏中的邮件系统,一般会限制标题,内容的长度,但由于客户端截取长度时的不正当操作,导致utf8串被从中间截断。比如标题长度上限是15个字节,然后玩家输入的标题占用了16个字节,而最后输入的一个汉字占用3个字节,如果直接按长度截断就会出现最后一个汉字被截掉了一个字节。数据传到服务端之后,服务端存库时,数据库会进行字符检查,就会发现有不正确的字符,而导致插入数据失败。

解决办法:首先客户端那边字符截断的方法要按照utf8的格式来进行过滤截取,比如上面的例子,最后应该截取3个字节而不是1个。对于服务端这边,为了保证数据能正确插入,可以对不正确字符进行替换,比较合适的方法就是单个字节的字符替换,可以的话增加日志记录,便于查找错误根源。客户端的截取代码可以参考下面的服务端替换代码来写。

// 获取utf8字符长度
int GetUTF8StrLen(IN const char chHead)
{
	if (0 == (0x80 & chHead))
	{
		return 1;
	}
	// 两个字节 110xxxxx 10xxxxxx
	else if (0xc0 == (0xe0 & chHead))
	{
		return 2;
	}
	// 三个字节 1110xxxx 10xxxxxx 10xxxxxx
	else if (0xe0 == (0xf0 & chHead))
	{
		return 3;
	}
	// 四个字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
	else if (0xf0 == (0xf8 & chHead))
	{
		return 4;
	}
	return 0;
}

// 10xxxxxx
bool IsUTF8SubChar(IN const char chSubChar)	
{

	return (0x80 == (0xc0 & chSubChar));
}

//////////////////////////////////////////////////////////////////////////
// UTF8字符串检查,注意pszString必须是utf8编码的字符串, chReplace为错误编码字符的替代符
// 返回值标识有没有字符被替换
bool UTF8Check(IN OUT char* pszString, const char chReplace /* = ' ' */)
{
	bool bHadReplaced = false;
	int nStrLen = strlen(pszString);
	if(nStrLen <= 0) return ;
	for (int i = 0; i < nStrLen;)
	{
		char& chTmp = *(pszString + i);
		int nSubLen = GetUTF8StrLen(chTmp);
		// 头字节错误
		if (0 == nSubLen)
		{
			chTmp = chReplace;
			i++;
			bHadReplaced = true;
		}
		// 1字节长度只要结构正确就没问题不用检查
		else if(1 == nSubLen) i++;
		// 超过1字节长度就要检查后面字节结构
		else if (nSubLen > 1)
		{
			// 剩下字节长度不够,全部替换
			if ((i + nSubLen) > nStrLen)
			{
				for (int k = i; k < nStrLen; k++) *(pszString + k) = chReplace;
				bHadReplaced = true;
				break;
			}

			int j = 1;
			for (; j < nSubLen; j++)
			{
				char& chSubChar = *(pszString + i + j);
				// 不是正确的子字符,就替换当前chTmp对应的utf8字符
				if (false == IsUTF8SubChar(chSubChar))
				{
					nSubLen = j + 1;
					// 如果当前字符是下一个utf8头字符,就不替换当前字符
					if (GetUTF8StrLen(chSubChar) > 0) nSubLen--;
					for (int k = 0; k < nSubLen; k++) *(pszString + k + i) = chReplace;	
					bHadReplaced = true;
					break;
				}
			}
			i += nSubLen;
		}
	}

	return bHadReplaced;
}


猜你喜欢

转载自blog.csdn.net/sirria1/article/details/52326530