最近在建词典,使用Trie字典树,需要把字符串分解成单个字。由于传入的字符串中可能包含中文或者英文,它们的字节数并不相同。一开始天真地认为中文就是两个字节,于是很happy地直接判断当前位置的字符的ASCII码是否处于0~127之间,如果是就提取一个字符,否则提取两个。在测试分字效果的时候,这种方法出了问题。比如我传一个“abcde一二三四五”进去,abcde可以正常分解成 a b c d e,而后面的“一二三四五”则成了乱码。

  于是我开启了谷歌之旅,搜索“如何在C++中将string中的中文分解成单个字”云云,搜索到的方法大多与我之前的方法雷同,把代码copy下来直接运行也是会出现乱码。我突然想到,linux下可能会出现中文乱码的原因之一就是编码问题,于是我打开了vim的配置文件,发现我确实是把中文设置成了utf-8。

  发现了这点之后,我专门搜索了utf-8,得知它是一种变长编码,具体规则如下:

  1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

  2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

  如表:

1字节 0xxxxxxx 
2字节 110xxxxx 10xxxxxx 
3字节 1110xxxx 10xxxxxx 10xxxxxx
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

  有了这个,思路就清晰了:首先,我要判断之后一个字是几个字节的,然后截取相应的字节数。于是有了如下代码:

 void Dictionary::splitWord(const string & word, vector<string> & characters)
{
int num = word.size();
int i = ;
while(i < num)
{
int size;
if(word[i] & 0x80)
{
if(word[i] & 0x20)
{
if(word[i] & 0x10)
{
if(word[i] & 0x08)
{
if(word[i] & 0x04)
{
size = ;
}else{
size = ;
}
}else{
size = ;
}
}else{
size = ;
}
}else{
size = ;
}
}else{
size = ;
}
string subWord;
subWord = word.substr(i, size);
characters.push_back(subWord);
i += size;
}
}

  if之中嵌套if,虽然过程很清晰,但是代码行数也太多了,于是对其进行修改,得到如下代码:

 void Dictionary::splitWord(const string & word, vector<string> & characters)
{
int num = word.size();
int i = ;
while(i < num)
{
int size = ;
if(word[i] & 0x80)
{
char temp = word[i];
temp <<= ;
do{
temp <<= ;
++size;
}while(temp & 0x80);
}
string subWord;
subWord = word.substr(i, size);
characters.push_back(subWord);
i += size;
}
}

  少了一半左右。

  分解出来的结果是存在vector容器中的,这个可以根据具体需要进行更改。

  最后发现,中文在utf-8编码中是三个字节的

  其实,只需要手动打印出对应string的size,就可以计算出每个字占多少字节了,当时怎么没发现呢?

最新文章

  1. 基础调试命令 - u/ub/uf
  2. php 简易购物习题
  3. 解决Odoo日期(时间)无效的问题 [转]
  4. 如何在Macbook Pro搭建PHP开发环境
  5. double与int类型自动转换
  6. leetcode@ [354] Russian Doll Envelopes (Dynamic Programming)
  7. Oralce_语法
  8. cocos2d-x 手势之简单实现
  9. 【HDOJ】2045 不容易系列之(3)—— LELE的RPG难题
  10. 在jsp中的css
  11. Day21 Django之Form文件上传、原生Ajax和实现抽屉实例
  12. Android判断网络连接状态
  13. C#:读取配置文件
  14. 转:HTTPS 升级指南
  15. Reids命令解析-RENAME
  16. Android开发之漫漫长途 番外篇——内存泄漏分析与解决
  17. Java经典编程题50道之四十五
  18. 【django之分页器】
  19. Python加密保护-对可执行的exe进行保护
  20. Struts2 action 跳转到web-inf下,

热门文章

  1. bzoj2395 [Balkan 2011]Timeismoney(最小乘积生成树+计算几何)
  2. Python3入门之软件安装
  3. 对于Discuz 及PHP的一点个人感受
  4. Exadata 18.1新特性--计算节点升级增强
  5. 14. 异步加载Js的方式有哪些?
  6. python大作业-图书管理系统
  7. numpy-1
  8. P3066 [USACO12DEC]逃跑的BarnRunning Away From (树上二分)
  9. es6 封装一个登录注册的验证滑块
  10. 通过CMD命令设置网络参数