最近在建词典,使用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,就可以计算出每个字占多少字节了,当时怎么没发现呢?

萌新笔记——C++里将string类字符串(utf-8编码)分解成单个字(可中英混输)的更多相关文章

  1. C++里将string类字符串(utf-8编码)分解成单个字(可中英混输)

    最近在建词典,使用Trie字典树,需要把字符串分解成单个字.由于传入的字符串中可能包含中文或者英文,它们的字节数并不相同.一开始天真地认为中文就是两个字节,于是很happy地直接判断当前位置的字符的A ...

  2. 萌新笔记——C++里创建 Trie字典树(中文词典)(一)(插入、遍历)

    萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...

  3. 萌新笔记——C++里创建 Trie字典树(中文词典)(二)(插入、查找、导入、导出)

    萌新做词典第二篇,做得不好,还请指正,谢谢大佬! 做好了插入与遍历功能之后,我发现最基本的查找功能没有实现,同时还希望能够把内存的数据存入文件保存下来,并可以从文件中导入词典.此外,数据的路径是存在配 ...

  4. 萌新笔记——C++里创建 Trie字典树(中文词典)(三)(联想)

    萌新做词典第三篇,做得不好,还请指正,谢谢大佬! 今天把词典的联想做好了,也是比较low的,还改了之前的查询.遍历等代码.  Orz 一样地先放上运行结果: test1 ID : char : 件 w ...

  5. hiho1482出勤记录II(string类字符串中查找字符串,库函数的应用)

    string类中有很多好用的函数,这里介绍在string类字符串中查找字符串的函数. string类字符串中查找字符串一般可以用: 1.s.find(s1)函数,从前往后查找与目标字符串匹配的第一个位 ...

  6. python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字

    python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字在字符串里面插入指定分割符的方法,先把字符串变成list然后用join方法变成字符串str=' ...

  7. Java学习笔记之:Java String类

    一.引言 字符串广泛应用在Java编程中,在Java中字符串属于对象,Java提供了String类来创建和操作字符串. 创建字符串最简单的方式如下: String str= "Hello w ...

  8. Java里的String类为什么是final的

    今天在看<图解设计模式>,里面出了一个问题“String类用final修饰,导致它无法被继承(扩展),这样做违反了开闭原则,这么做有什么正当理由?” 答案是效率和安全性  首先是效率,由于 ...

  9. C++ primer plus读书笔记——第16章 string类和标准模板库

    第16章 string类和标准模板库 1. string容易被忽略的构造函数: string(size_type n, char c)长度为n,每个字母都为c string(const string ...

随机推荐

  1. jQuery-1.9.1源码分析系列(九) CSS操作

    jquery.fn.css获取当前jQuery所匹配的元素中第一个元素的属性值[$(…).css(cssName),注意这个cssName可以是数组]或给当前jQuery所匹配的每个元素设置样式值[$ ...

  2. 一步一步开发Game服务器(二)完成登陆,聊天

    我知道这样的文章在博客园已经多的大家都不想看了,但是这是我的系列文章开始,请各位大神见谅了. 多线程,线程执行器,(详见),socket通信相关 (详见) 本人blog相关文章测试代码,示例,完整版s ...

  3. SQL Server中smalldatetime的日期范围为何是[1900-01-01,2079-06-06]

    本文目录列表: 1.SQL Server中的基准日期 2.smalldatetime的日期范围 3.smalldatetime的日期范围和无符号2字节整数的关系 4.总结语 5.参考清单列表   SQ ...

  4. .NET设计模式(2):1.2 抽象工厂模式(Abstract Factory)

    概述 抽象工厂模式(Abstract Factory)是所有形态的工厂模式中最为抽象和最具一般性的一种形态.抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式.抽象工厂模式可以向客户端提供一个接口 ...

  5. 异步与并行~ReaderWriterLockSlim实现的共享锁和互斥锁

    返回目录 在System.Threading.Tasks命名空间下,使用ReaderWriterLockSlim对象来实现多线程并发时的锁管理,它比lock来说,性能更好,也并合理,我们都知道lock ...

  6. 图解SQL的Join(转)

    对于SQL的Join,在学习起来可能是比较乱的.我们知道,SQL的Join语法有很多inner的,有outer的,有left的,有时候,对于Select出来的结果集是什么样子有点不是很清楚.Codin ...

  7. Java--设计模式心得体会

    1.策略模式: 策略模式就是将能够通用的算法,封装成不同的组件,实现同一个接口,使之可以互换. 例子:SpringMVC的9大组件,都采用策略模式.比如HandlerMethodArgumentRes ...

  8. ADO.NET 中的新增功能

    ADO.NET 中的新增功能: .NET Framework (current version) 以下是 .NET Framework 4.5 中 ADO.NET 的新增功能. SqlClient D ...

  9. JavaScript判断变量值简单的方法

    今天在看一个动态web表单设计器的时候发现项目中的 一个写法 function sum_total(v){ if (!v) { v= 0; } } !v  这是什么写法?不过可以肯定的是,这是一种判断 ...

  10. ae 地理坐标与投影坐标转换 [转]

    转载地址:http://blog.163.com/lai_xiao_hui/blog/static/123037324201151443221942/ 代码是将WGS84地理坐标转换为WGS84UTM ...