今天在提取正文中跟关键词相关的一段文字时,总是出现乱码,只是简单的截取了一下长度,结果各种乱码
后来想到之前处理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
|
写了个小程序,用于提取正文中和关键词相关的一段文字:
#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; }