使用C++读取UTF8及GBK系列的文本方法及原理

本文介绍了C++读取UTF-8和GBK编码文本的原理,包括UTF-8的可变长编码方式和GBK的双字节变长编码。通过定义抽象类Text和实现GBKText、UtfText,利用简单工厂模式实现不同编码文本的透明读取。
摘要由CSDN通过智能技术生成

作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4374404.html

1.读取UTF-8编码文本原理

首先了解UTF-8的编码方式,UTF-8采用可变长编码的方式,一个字符可占1字节-6字节,其中每个字符所占的字节数由字符开始的1的个数确定,具体的编码方式如下:

U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

因此,对于每个字节如果起始位为“0”则说明,该字符占有1字节。

如果起始位为“10”则说明该字节不是字符的起始字节。

如果起始为为$n$个“1”+1个“0”,则说明改字符占有$n$个字节。其中$1 \leq n \leq 6$。

因此对于UTF-8的编码,我们只需要每次计算每个字符开始字节的1的个数,就可以确定这个字符的长度。

 

2.读取GBK系列文本原理

对于ASCII、GB2312、GBK到GB18030编码方法是向下兼容的 ,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。

在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。

因此我们只需处理好GB18130,就可以处理与他兼容的所有编码,对于GB18130使用双字节变长编码。

单字节部分从 0x0~0x7F 与 ASCII 编码兼容。双字节部分,首字节从 0x81~0xFE,尾字节从 0x40~0x7E以及 0x80~0xFE,与GBK标准基本兼容。

因此只需检测首字节是否小于0x81即可确定其为单字节编码还是双字节编码。

 

3.C++代码实现

对于一个语言处理系统,读取不同编码的文本应该是最基础的需求,文本的编码方式应该对系统其他调用者透明,只需每次获取一个字符即可,而不需要关注这个文本的编码方式。从而我们定义了抽象类Text,及其接口ReadOneChar,并使两个文本类GbkText和UtfText继承这个抽象类,当系统需要读取更多种编码的文件时,只需要定义新的类然后继承该抽象类即可,并不需要更改调用该类的代码。从而获得更好的扩展性。

更好的方式是使用简单工厂模式,使不同的文本编码格式对于调用类完全透明,简单工厂模式详解请参看:C++实现设计模式之 — 简单工厂模式

其中Text抽象类的定义如下:

 1 #ifndef TEXT_H
 2 #define TEXT_H
 3 #include <iostream>
 4 #include <fstream>
 5 using namespace std;
 6 class Text
 7 {
 8     protected:
 9         char * m_binaryStr;
10         size_t m_length;
11         size_t m_index;
12     public:
13         Text(string path);
14         void SetIndex(size_t index);
15         virtual bool ReadOneChar(string &oneChar) = 0;
16         size_t Size();
17         virtual ~Text();
18 };
19 #endif
View Code

Text抽象类的实现如下:

 1 #include "Text.h"
 2 using namespace std;
 3 Text::Text(string path):m_index(0)
 4 {
 5     filebuf *pbuf;
 6     ifstream filestr;
 7     // 采用二进制打开 
 8     filestr.open(path.c_str(), ios::binary);
 9     if(!filestr)
10     {
11         cerr<<path<<" Load text error."<<endl;
12         return;
13     }
14     // 获取filestr对应buffer对象的指针 
15     pbuf=filestr.rdbuf();
16     // 调用buffer对象方法获取文件大小
17     m_length=(int)pbuf->pubseekoff(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值