关于utf8字符串处理,字符串截取乱码问题

今天在提取正文中跟关键词相关的一段文字时,总是出现乱码,只是简单的截取了一下长度,结果各种乱码

后来想到之前处理gbk字符串时,根据第一个字符的无符号整型值来判断这个字占多少个字符,如果大于0x80就是两个字符,否则就是一个字符,修改完之后,还是出现乱码

这才发现程序里取到的字符串全是utf8的(唉,改别人的程序,不知道会遇到什么问题),去网上查了下utf8的编码规则:

Unicode/UCS-4
bit数
UTF-8
byte数
备注
0000 ~
007F
0~7
0XXX XXXX
1
 
0080 ~
07FF
8~11
110X XXXX
10XX XXXX
2
 
0800 ~
FFFF
12~16
1110XXXX
10XX XXXX
10XX XXXX
3
基本定义范围:0~FFFF
1 0000 ~
1F FFFF
17~21
1111 0XXX
10XX XXXX
10XX XXXX
10XX XXXX
4
Unicode6.1定义范围:0~10 FFFF
20 0000 ~
3FF FFFF
22~26
1111 10XX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
5
说明:此非unicode编码范围,属于UCS-4 编码
早期的规范UTF-8可以到达6字节序列,可以覆盖到31位元(通用字符集原来的极限)。尽管如此,2003年11月UTF-8 被 RFC 3629 重新规范,只能使用原来Unicode定义的区域, U+0000到U+10FFFF。根据规范,这些字节值将无法出现在合法 UTF-8序列中
400 0000 ~
7FFF FFFF
27~31
1111 110X
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
10XX XXXX
6

根据上面这个表,就可以判断某个字所占字符数,跟gbk的处理方式一样,也是遍历字符串,根据第一个字符的值判断需要占用多少字节

写了个小程序,用于提取正文中和关键词相关的一段文字:

#include <string>

class CUtfStr
{
public:
	CUtfStr(const char *_utf);
	~CUtfStr();
	int getwordnum();			//计算utf8字符串中有多少字
	int getbytenum(char ch);	//获取当前字节表示这个字占多少字节
	int getDesc(char *desc, char *keywords, int nWordNum);	//获取和关键词相关的一段内容,关键词必须用*分割

private:
	char *utfStr;
};

CUtfStr::CUtfStr(const char *_utf)
{
	int nLen = strlen(_utf);
	utfStr = new char[nLen+10];
	memset(utfStr, 0, nLen+10);
	sprintf(utfStr, "%s", _utf);
}

CUtfStr::~CUtfStr()
{
	delete [] utfStr;
}

int CUtfStr::getwordnum()
{
	char *pos = utfStr;
	int nWordNum = 0;
	while(pos && pos <= utfStr+strlen(utfStr)-1)
	{
		pos += getbytenum(*pos);
		nWordNum++;
	}
	return nWordNum;
}

int CUtfStr::getbytenum(char ch)
{
	int nCode = (unsigned char)ch;
	if(nCode < 128)
		return 1;
	else if(nCode>=192 && nCode <= 223)
		return 2;
	else if(nCode >= 224 && nCode <= 239)
		return 3;
	else if(nCode >= 240 && nCode <= 247)
		return 4;
	else if(nCode >= 248 && nCode <= 251)
		return 5;
	else if(nCode >= 252 && nCode <= 253)
		return 6;
	else
		return 7;
}

int CUtfStr::getDesc(char *desc, char *keywords, int nWordNum)
{
	char *pstart = keywords;
	char *pos = strstr(pstart, "*");
	bool bFind = false;
	int nWordLen = -1;
	char sword[1024];
	while(pos)
	{
		memset(sword, 0, 1024);
		strncpy(sword, pstart, pos-pstart);
		pstart = pos+1;
		pos = strstr(pstart, "*");
		
		//printf("word:%s\n", sword);
		if(strstr(utfStr, sword))
		{
			bFind = true;
			nWordLen = strlen(sword);
			break;
		}
	}
	if(bFind == false && pstart < keywords+strlen(keywords))
	{
		memset(sword, 0, 1024);
		strncpy(sword, pstart, keywords + strlen(keywords) - pstart);
		//printf("word:%s\n", sword);
		
		if(strstr(utfStr, sword))
		{
			bFind = true;
			nWordLen = strlen(sword);
		}
	}
	
	if(bFind && nWordLen > 0)
	{
		//找到词了
		char *wordpos = strstr(utfStr, sword);
		char *beforePos = (char*)utfStr;
		while(beforePos && beforePos < wordpos)
		{
			if(wordpos-beforePos <= 12)
				break;
			beforePos = beforePos + getbytenum(*beforePos);
		}
		if(beforePos && beforePos < wordpos)
			strncpy(desc, beforePos, wordpos-beforePos);
		else
			strncpy(desc, utfStr, wordpos-utfStr);
		strcat(desc, "<span style=\"color:red;\">");
		strcat(desc, sword);
		strcat(desc, "</span>");
		char *afterpos = wordpos+nWordLen;
		int nAfternum = 0;
		while(afterpos)
		{
			int nCode = (unsigned char)(*afterpos);
			afterpos = afterpos + getbytenum(*afterpos);
			nAfternum++;
			
			if(nAfternum >= nWordNum-8)
				break;
		}
		if(afterpos)
			strncat(desc, wordpos+nWordLen, afterpos-(wordpos+nWordLen));
		else
			strcat(desc, wordpos+nWordLen);
	}
	else
	{
		//没找到,就从头取40个字
		char *pos = (char*)utfStr;
		int num = 0;
		while(pos && pos <= utfStr+strlen(utfStr)-1)
		{
			pos = pos + getbytenum(*pos);
			num++;
			if(num >= nWordNum)
				break;
		}
		strncat(desc, utfStr, pos-utfStr);
	}
	return 1;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值