ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

分字(汉字编码)

2021-11-30 21:35:11  阅读:207  来源: 互联网

标签:字符 字节 分字 汉字 汉字编码 len byte ASCII


关于使用GBK和UTF8进行汉字编码的学习总结。

1 原理总结

1.1 GBK(GB)

GBK编码规则简述:

  • 使用1-2个字节表示一个字符,从左向右一个字节一个字节识别。
  • 若当前字节首位为0,则该字符用1个字节表示(ASCII字符)。
  • 若当前字节首位为1,则该字符用2个字节表示(汉字)。

列表如下:

1字节字符(ASCII字符) 2字节字符(汉字)
0XXXXXXX 1XXXXXXX XXXXXXXX

其中"X"代表0或1。

1.2 UTF8

UTF8编码规则简述:

  • 使用1-6个字节表示一个字符,从左向右一个字节一个字节识别。
  • 若当前字节首位为0,则该字符用1个字节表示(ASCII字符,同GBK)。
  • 当字节数大于2时(此时表示汉字),假设该字符有n个字节,该字符的表示与n的关系如下:
    • 首字节:前n位是1,n+1位是0,后面任意。
    • 其余n-1个字节,前两位必须是10,后面任意。

注意汉字的编码前面至少有2个1(有几个1就表示该汉字用几个字节表示)。

列表如下:

1字节字符(ASCII字符) 2字节字符(汉字) 3字节字符(汉字) 4字节字符(汉字) 5字节字符(汉字) 6字节字符(汉字)
0XXXXXXX 110XXXXX
10XXXXXX
1110XXXX
10XXXXXX
10XXXXXX
11110XXX
10XXXXXX
10XXXXXX
10XXXXXX
111110XX
10XXXXXX
10XXXXXX
10XXXXXX
10XXXXXX
1111110X
10XXXXXX
10XXXXXX
10XXXXXX
10XXXXXX
10XXXXXX

2 代码实现

2.1 数据

因为重在试验,数据非常简单,是自己写的如下一段话。

Google是拥有超过10亿用户的公司 也是全球最大的搜索引擎公司

分别在记事本(windows)中用utf8和gbk(ANSI)编码保存。
要求每个字符用空格隔开,并统计字符个数,包括汉字和数字、英文字符等ASCII字符。

2.2 C++实现

C++的一个字符(char类型)只有8位,即一个字节,所以是不能直接表示一个汉字的。需要根据相应编码的原理来识别汉字。把读到的内容转换为字符数组后,就根据具体的编码规则一个字符一个字符的识别汉字(或ASCII字符)。具体就是判断当前要识别的汉字(或ASCII字符)由几个字节(即C++字符)组成,把这几个C++字符保存到一个字符串中再输出,就可以输出一个特定编码的汉字(或ASCII字符)了。

2.2.1 读文件

因为需要按位操作,最好用二进制的方式读文件。

ifstream f_in("path/to/utf-8_input.txt",ios::in|ios::binary);//以二进制形式读文件

2.2.2 获取文件长度(字节数)

f_in.seekg(0,ios::end);//把指针移到文件末尾
f_len=f_in.tellg();//获取文件长度
f_in.seekg(0,ios::beg);//把指针移到文件开头

2.2.3 把文件内容保存到字符串中,方便操作。

char *buffer=new char[f_len];//开辟文件长度大小的空间
f_in.read(buffer,f_len);//按字节读文件,全部存到buffer中
string s=buffer;//buffer的内容存到字符串,方便操作

2.2.4 进行字符识别

这里可以使用C++自带的bitset进行操作,非常方便。bitset类似一个bool类型的数组,每个C++字符(尽管它可能没有意义)都可以转换成一个bitset对象,然后就可以判断以它为首字节的汉字(或ASCII字符)由几个字节组成了。需要注意的是,对于bitset对象,首位在最高位,如果用byte表示一个C++字符转换来的二进制数组,则byte[7]是首位。
识别gbk字符的实现如下

for(int i=0; i<f_len;)
{
    bitset<8> byte(s[i]);//转二进制
    if(s[i]==' ')//遇到空格跳过(utf-8,gbk,ascii码空格均为0x20)
    {
        i=i+1;
        continue;
    }
    else if(byte[7]==0) c_len=1;//首位是0,1字节
    else if(byte[7]==1) c_len=2;//首位是1,2字节
    string c=s.substr(i,c_len);
    cout<<c;
    f_out<<c;
    if(i+c_len<f_len)//最后一个字符后面没有空格
    {
        cout<<' ';
        f_out<<' ';
    }
    num++;
    i=i+c_len;
}

识别utf8字符的实现如下

for(int i=0; i<f_len;)
{
    bitset<8> byte(s[i]);//单字节转二进制
    if(s[i]==' ')//遇到空格跳过(utf-8,gbk,ascii码空格均为0x20)
    {
        i=i+1;
        continue;
    }
    else if(byte[7]==0) c_len=1;//0xxxxxxx,1字节
    else if(byte[5]==0) c_len=2;//110xxxxx,2字节
    else if(byte[4]==0) c_len=3;//11110xxx,3字节
    else if(byte[3]==0) c_len=4;//111110xx,4字节
    else if(byte[2]==0) c_len=5;//1111110x,5字节
    else if(byte[1]==0) c_len=6;//11111110,6字节
    string c=s.substr(i,c_len);
    f_out<<c;
    if(i+c_len<f_len) f_out<<' ';//最后一个字符后面没有空格
    num++;
    i=i+c_len;
}

遗憾的是,由于控制台只支持gbk编码,打印utf8字符后会乱码;因此utf8编码的结果只能输出到文件中,并且不能在utf8文件中输出汉字(使用键盘打字,用ofstream输出到文件中),因为C++字符串中的汉字也是gbk编码的,输出到utf8文件中会乱码。

2.3 python实现

python可以直接识别GBK和UTF8编码的字符,先用字符串的split函数转成成字符串列表,再对列表中每一个字符串进行遍历即可。注意用在open函数中指定文件编码。除此之外,结果也可以在控制台和文件中同时输出。

参考文献

[1] 李老师的讲义-Chinese-encoding

标签:字符,字节,分字,汉字,汉字编码,len,byte,ASCII
来源: https://www.cnblogs.com/yumengliu/p/15625484.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有