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

来源:互联网 发布:淘宝怎么买枪 编辑:程序博客网 时间:2024/05/22 17:23

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

后来想到之前处理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;elsereturn 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);elsestrncpy(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));elsestrcat(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;}


1 0