C++语言读取UTF-8及GBK系列的文本方法及原理
小职 2017-11-15 来源 :网络 阅读 949 评论 0

摘要:本篇C++语言教程将为大家讲解C++语言编程的知识点,看完这篇文章会让你对C++语言编程的知识点有更加清晰的理解和运用。

本篇C++语言教程将为大家讲解C++语言编程的知识点,看完这篇文章会让你对C++语言编程的知识点有更加清晰的理解和运用。

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≤n≤6。

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

2.读取GBK系列文本原理

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

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

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

单字节部分从 0×0~0x7F 与 ASCII 编码兼容。双字节部分,首字节从 0×81~0xFE,尾字节从 0×40~0x7E以及 0×80~0xFE,与GBK标准基本兼容。

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

3.C++代码实现

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

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

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

#ifndef TEXT_H#define TEXT_H#include <iostream>#include <fstream>using namespace std;class Text

{

    protected:

        char * m_binaryStr;

        size_t m_length;

        size_t m_index;

    public:

        Text(string path);

        void SetIndex(size_t index);

        virtual bool ReadOneChar(string &oneChar) = 0;

        size_t Size();

        virtual ~Text();

};#endif

Text抽象类的实现如下:

#include "Text.h"using namespace std;

Text::Text(string path):m_index(0)

{

    filebuf *pbuf;

    ifstream filestr;

    // 采用二进制打开

    filestr.open(path.c_str(), ios::binary);

    if(!filestr)

    {

        cerr<<path<<" Load text error."<<endl;

        return;

    }

    // 获取filestr对应buffer对象的指针

    pbuf=filestr.rdbuf();

    // 调用buffer对象方法获取文件大小

    m_length=(int)pbuf->pubseekoff(0,ios::end,ios::in);

    pbuf->pubseekpos(0,ios::in);

    // 分配内存空间

    m_binaryStr = new char[m_length+1];

    // 获取文件内容

    pbuf->sgetn(m_binaryStr,m_length);

    //关闭文件

    filestr.close();

}

void Text::SetIndex(size_t index)

{

    m_index = index;

}

size_t Text::Size()

{

    return m_length;

}

 

Text::~Text()

{

    delete [] m_binaryStr;

}

GBKText类的定义如下:

#ifndef GBKTEXT_H#define GBKTEXT_H#include <iostream>#include <string>#include "Text.h"using namespace std;class GbkText:public Text

{public:

    GbkText(string path);

    ~GbkText(void);

    bool ReadOneChar(string & oneChar);

};#endif

GBKText类的实现如下:

#include "GbkText.h"

GbkText::GbkText(string path):Text(path){}

GbkText::~GbkText(void) {}bool GbkText::ReadOneChar(string & oneChar)

{

    // return true 表示读取成功,

    // return false 表示已经读取到流末尾

    if(m_length == m_index)

        return false;

        if((unsigned char)m_binaryStr[m_index] < 0x81)

    {

        oneChar = m_binaryStr[m_index];

        m_index++;

    }

    else

    {

        oneChar = string(m_binaryStr, 2);

        m_index += 2;

    }

    return true;

}

UtfText类的定义如下:

#ifndef UTFTEXT_H#define UTFTEXT_H#include <iostream>#include <string>#include "Text.h"using namespace std;class UtfText:public Text

{public:

    UtfText(string path);

    ~UtfText(void);

    bool ReadOneChar(string & oneChar);private:

    size_t get_utf8_char_len(const char & byte);

};#endif

UtfText类的实现如下:

#include "UtfText.h"

UtfText::UtfText(string path):Text(path){}

UtfText::~UtfText(void) {}bool UtfText::ReadOneChar(string & oneChar)

{

    // return true 表示读取成功,

    // return false 表示已经读取到流末尾

    if(m_length == m_index)

        return false;

    size_t utf8_char_len = get_utf8_char_len(m_binaryStr[m_index]);

    if( 0 == utf8_char_len )

    {

            oneChar = "";

            m_index++;

        return true;

    }

    size_t next_idx = m_index + utf8_char_len;

    if( m_length < next_idx )

    {

        //cerr << "Get utf8 first byte out of input src string." << endl;

        next_idx = m_length;

    }

    //输出UTF-8的一个字符

    oneChar = string(m_binaryStr + m_index, next_idx - m_index);

    //重置偏移量

    m_index = next_idx;

    return true;

}

size_t UtfText::get_utf8_char_len(const char & byte)

{

    // return 0 表示错误

    // return 1-6 表示正确值

    // 不会 return 其他值

 

    //UTF8 编码格式:

    //     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  

 

    size_t len = 0;

    unsigned char mask = 0x80;

    while( byte & mask )

    {

        len++;

        if( len > 6 )

        {

            //cerr << "The mask get len is over 6." << endl;

            return 0;

        }

        mask >>= 1;

    }

    if( 0 == len)

    {

        return 1;

    }

    return len;

}

工厂类TextFactory的类定义如下:

#ifndef TEXTFACTORY_H#define TEXTFACTORY_H#include <iostream>#include "Text.h"#include "UtfText.h"#include "GbkText.h"using namespace std;class TextFactory

{

    public:

        static Text * CreateText(string textCode, string path);

};#endif

工厂类的实现如下:

#include "TextFactory.h"#include "Text.h"

Text * TextFactory::CreateText(string textCode, string path)

{

    if( (textCode == "utf-8")

                || (textCode == "UTF-8")

                || (textCode == "ISO-8859-2")

                || (textCode == "ascii")

                || (textCode == "ASCII")

                || (textCode == "TIS-620")

                || (textCode == "ISO-8859-5")

                || (textCode == "ISO-8859-7") )

    {

        return new UtfText(path);

    }

    else if((textCode == "windows-1252")

                || (textCode == "Big5")

                || (textCode == "EUC-KR")

                || (textCode == "GB2312")

                || (textCode == "ISO-2022-CN")

                || (textCode == "HZ-GB-2312")

                || (textCode == "gb18030"))

    {

        return new GbkText(path);

    }

    return NULL;

}

测试的Main函数如下:

#include <stdio.h>#include <string.h>#include <iostream>#include "Text.h"#include "TextFactory.h"#include "CodeDetector.h"using namespace std;int main(int argc, char *argv[]){

    string path ="日文";

    string code ="utf-8";

    Text * t = TextFactory::CreateText(code, path);

    string s;

    while(t->ReadOneChar(s))

    {

        cout<<s;

    }

    delete t;

}

 

以上,关于C++的全部内容讲解完毕啦,欢迎大家继续关注!更多关于C++的干货请关注职坐标C++频道!

本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程