1. 概要:
- 在实际的工程开发中,有时候需要统计utf8字符串中字符的个数,单纯统计字节个数是不行的,因为一个字符有时候所占的空间不止一个字节,比如UTF-8编码方案中:一个英文字符占1个字节,一个中文字符占三个字节(在其他编码方案中一个中文字符可能占两个字节)。
- 在本文的实战演练板块,提供了获取UTF-8字符串中的字符个数以及将字符串中的字符全部提取出来再以字符为单位保存在向量中的实战代码。
- 详情点击:https://blog.csdn.net/COCO56/article/details/91457885
2. 源码
static int GetUtf8LetterNumber(const char *s)
{
int i = 0, j = 0;
while (s[i])
{
//if ((s[i] & 0b11000000) != 0b10000000) j++;
if ((s[i] & 0xc0) != 0x80) j++;
i++;
}
return j;
}
3. 说明
0xC0=0b11000000
0x80=0b10000000
& 代表 按位逻辑与
UTF-8编码规则:如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的字节数,其余各字节均以10开头。UTF-8转换表表示如下:
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 | 1110 XXXX 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 | |
400 0000~7FFF FFFF | 27~31 | 1111 110X 10XX XXXX 10XX XXXX 10XX XXXX 10XX XXXX 10XX XXXX | 6 | |
注:5个字节和6个字节的非unicode编码范围,属于UCS-4 编码早期的规范UTF-8可以到达6字节序列,可以覆盖到31位元(通用字符集原来的极限)。尽管如此,2003年11月UTF-8 被 RFC 3629 重新规范,只能使用原来Unicode定义的区域, U+0000到U+10FFFF。根据规范,这些字节值将无法出现在合法 UTF-8序列中
4. 实战演练
下面是我开发的游戏引擎中的一个模块,用于帮助其他开发者处理快速字符串相关的事件。
- QString.h
#pragma execution_character_set("utf-8")
/*开头第一句主要是为了完美解决C++ VS输出中文乱码痛点
概要:
使用高版本的VS,将源代码文件保存为utf-8格式,接着在源码开头处告诉编译器要用utf-8编码方案进行解析源代码。
这样做直接就可以了正常解析源码中的中文了,无需使用xml文档或者对源码中的中文字符进行额外的转码处理。
具体参考:https://blog.csdn.net/COCO56/article/details/91350176
*/
#pragma once
/*QuickEngine为我自主开发的游戏引擎
// #include "QuickEngine.h"
// QString是QuickEngine中的一个模块,用于处理快速字符串相关的事件
*/
#include <vector>
#include <string>
using namespace std;
class QString
{
enum CharSet
{
UTF_8 = 0
};
public:
/*暂时不处理非UTF_8编码的处理*/
//获取一个字符串中有多少个字符
static int getStringLetterNumber(string str, CharSet cs = UTF_8);
//将一个字符串中的所有字符都识别分离出来,并将每个字符保存为vector<string>中的一个元素
static vector<string> strToVector(string str, CharSet cs = UTF_8);
};
- QString.cpp
#pragma execution_character_set("utf-8")
#include "QString.h"
int QString::getStringLetterNumber(string str, CharSet cs)
{
if (cs != UTF_8)
{
return -1;
}
const char* s = str.c_str();
int i = 0, j = 0;
while (s[i])
{
if ((s[i] & 0b11000000) != 0b10000000) j++;
i++;
}
return j;
}
vector<string> QString::strToVector(string str, CharSet cs)
{
vector<string> vstr;
if (cs != UTF_8) { return vstr; };
const char* s = str.c_str();
int i = 1, j = 0, l=0, sum=0;
while (1)
{
if (s[i])//未到字符串的结尾,即未读取到'\0'
{
if ((s[i] & 0b11000000) != 0b10000000)//读取到一个新字符的开头
{
l = i - j;
//CCLOG("f = %d, j=%d, l=%d, s=%s", flag, j, l, str.substr(j, l).c_str());
vstr.push_back(str.substr(j, l));
j = i;
}
i++;
}
else
{
l = i - j;
vstr.push_back(str.substr(j, l));
break;
}
}
return vstr;
}