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


      最近在建词典,使用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

      

      

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

     1 void Dictionary::splitWord(const string & word, vector<string> & characters)
     2 {
     3     int num = word.size();
     4     int i = 0;
     5     while(i < num)
     6     {
     7         int size;    
     8         if(word[i] & 0x80)
     9         {
    10             if(word[i] & 0x20)
    11             {
    12                 if(word[i] & 0x10)
    13                 {
    14                     if(word[i] & 0x08)
    15                     {
    16                         if(word[i] & 0x04)
    17                         {
    18                                 size = 6;
    19                         }else{
    20                             size = 5;
    21                         }
    22                     }else{
    23                         size = 4;
    24                     }
    25                 }else{
    26                     size = 3;
    27                 }
    28             }else{
    29                 size = 2;
    30             }
    31         }else{
    32             size = 1;
    33         }
    34         string subWord;
    35         subWord = word.substr(i, size);
    36         characters.push_back(subWord);
    37         i += size;
    38     }
    39 }

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

     1 void Dictionary::splitWord(const string & word, vector<string> & characters)
     2 {
     3     int num = word.size();
     4     int i = 0;
     5     while(i < num)
     6     {
     7         int size = 1;
     8         if(word[i] & 0x80)
     9         {
    10             char temp = word[i];
    11             temp <<= 1;
    12             do{
    13                 temp <<= 1;
    14                 ++size;
    15             }while(temp & 0x80);
    16         }
    17         string subWord;
    18         subWord = word.substr(i, size);
    19         characters.push_back(subWord);
    20         i += size;
    21     }
    22 }

      少了一半左右。

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

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

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

  • 相关阅读:
    DNA 序列翻译
    python3 练习题100例 (二十九)猴子吃桃问题
    python3 练习题100例 (二十八)打印一定范围内的素数
    python3 练习题100例 (二十七)列表元素改写
    python3 练习题100例 (二十六)回文数判断
    python3 练习题100例 (二十五)打印一个n层金字塔
    python3 练习题100例 (二十四)打印完数
    python3 练习题100例 (二十三)与7相关的数
    python3 练习题100例 (二十二)输入两个字符串,输出两个字符串集合的并集
    python3 练习题100例 (二十一)打印一定范围内的水仙花数
  • 原文地址:https://www.cnblogs.com/chinxi/p/6129774.html
Copyright © 2020-2023  润新知