关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » C/C++ »C++读取UTF-8及GBK系列的文本方法及原理

    C++读取UTF-8及GBK系列的文本方法及原理

    2015-03-28 00:00:00 出处:melonstreet
    分享

    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;
    }
    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    Destoon 模板存放规则及语法参考

    Destoon系统常量与变量

    Destoon系统目录文件结构说明

    Destoon 系统安装指南

    Destoon会员公司主页模板风格添加方法

    Destoon 二次开发入门

    Microsoft 将于 2026 年 10 月终止对 Windows 11 SE 的支持

    Windows 11 存储感知如何设置?了解Windows 11 存储感知开启的好处

    Windows 11 24H2 更新灾难:系统升级了,SSD固态盘不见了...

    小米路由器买哪款?Miwifi热门路由器型号对比分析

    IT头条

    Synology 对 Office 套件进行重大 AI 更新,增强私有云的生产力和安全性

    01:43

    StorONE 的高效平台将 Storage Guardian 数据中心占用空间减少 80%

    11:03

    年赚千亿的印度能源巨头Nayara 云服务瘫痪,被微软卡了一下脖子

    12:54

    国产6nm GPU新突破!砺算科技官宣:自研TrueGPU架构7月26日发布

    01:57

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    技术热点

    如何删除自带的不常用应用为windows 7减负

    MySQL中多表删除方法

    改进的二值图像像素标记算法及程序实现

    windows 7 32位系统下手动修改磁盘属性例如M盘修改为F盘

    windows 7中怎么样在家庭组互传文件

    Linux应用集成MySQL数据库访问技巧

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。