您的位置:首页 > 其它

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

2016-08-11 14:12 555 查看
今天在提取正文中跟关键词相关的一段文字时,总是出现乱码,只是简单的截取了一下长度,结果各种乱码

后来想到之前处理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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c utf8 乱码 字符串 截取