zoukankan      html  css  js  c++  java
  • Qt之QTextCodec乱谈

    何处开始呢?

    一旦在Qt程序中出现latin1字符集以外的字符,几乎大家无一例外的会用到 QTextCodec。

    而不少网友不分青红皂白,一旦用到中文,就同时使用下面3条指令(其中textc 取为 gb18030 或 utf8,还有的会选用system)。

    QTextCodec::setCodecForCStrings(textc);
    QTextCodec::setCodecForTr(textc);
    QTextCodec::setCodecForLocale(textc);

    可是这3个东西有什么用呢?QTextCodec是做什么用的?

    字符串、字节流

    在C和C++中,我们一般都是将 "hello world!" 这种称为字符串(窄字符串、C传统字符串、char*字符串...)

    但目前来说,当我们提字符串时,一般是一个Unicode字符串,其由一个一个的unicode字符构成;当我们提字节流时,是指一个一个的字节。

    或许,我们可以说,ANSI C、C++截止目前只有字节流,而缺乏对字符串的支持。

    Qt 为字节流和字符串分别提供了 QByteArray 和 QString 两个类(还有QLatin1String等其他类,但这两个是最主要的)。当我们涉及到IO时,比如读写文件、读写网络socket、控制台(终端)输入 输出、读写串口... 操作的都是字节流,如果我们此时需要的操作的内容是字符串,则需要二者之间的相互转换。

    QTextCodec做什么?

    在 java、C#、python等语言都内置支持unicode字符串的情况下,C、C++ 一直以来对unicode却没有提供任何直接的支持(尽管有个所谓的宽字符wchar_t,但却不能解决什么问题)。即使是下一代标准(C++0x, C1x),对unicode也只是提供了一部分支持,真...

    标准对unicode缺乏支持,各个编译器对编码的支持又严重不一,这对于一个需要unicode字符串而又要夸平台的C++的库Qt来说,还真是一个挑战。Qt为解决这个问题提供了QTextCodec。

    QTextCodec 提供的是 字符串 和 字节流 之间的相互转换(也就是字符的编解码)。

    为了了解 QTextCodec 究竟是做了什么,我们不妨先定义自己的一个自定义QTextCodec

    • 定义一个类似latin1的单字节的字符集
      • 共 0~255 这256个码位
      • 与latin1相比,只不过是a-z和A-Z都反了一下序
    • 比如,对与字节流"x68x65x6cx6cx6fx20x77x6fx72x6cx64x21"
      • 按照latin1来解码,则是 u"hello world!"
      • 按照我们的自定义编码,则是无意义的 u"svool dliow!"

     

    class DbzhangCodec:public QTextCodec
    {
    public:
        DbzhangCodec(){}
        ~DbzhangCodec(){}
    
        QString convertToUnicode(const char *chars, int len, ConverterState *) const
        {
            if (len <= 0 || chars == 0)
                return QString();
            QString r(len);
            for (int i=0; i<len; ++i) {
                if (chars[i] > 'a' && chars[i] < 'z')
                    r[i] = 'a' + 'z' - chars[i];
                else if (chars[i] > 'A' && chars[i] < 'Z')
                    r[i] = 'A' + 'Z' - chars[i];
                else
                    r[i] = QLatin1Char(chars[i]);
            }
            return r;
        }
        QByteArray convertFromUnicode(const QChar *in, int len, ConverterState *) const
        {
            QByteArray r(len, '?');
            for (int i=0; i<len; ++i) {
                int u = in[i].unicode();
                if (u > 255)
                    r[i] = '?';
                else if (u > 'a' && u < 'z')
                    r[i] = 'z' - u + 'a';
                else if (u > 'A' && u < 'Z')
                    r[i] = 'Z' - u + 'A';
                else
                    r[i] = u;
            }
            return r;
        }
    
        QByteArray name() const {return "dbzhang800";}
        QList<QByteArray> aliases() const{return QList<QByteArray>()<<"dbzhang-800";}
        int mibEnum() const{return 2011;}
    };

    这个类主要就是要实现两个函数,一个是字节流到unicode的转换,一个是unicode到字节流的转换。

    使用举例

    定义了一个自定义的int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTextCodec * codec = new DbzhangCodec; QTextCodec::setCodecForCStrings(codec); qDebug()<<QString("hello world!"); return 0; }

    注意:此处使用 new,但却没有相应的 delete。这不会造成内存泄漏,因为Qt创建每一个TextCodec之时都会将其放入到一个QList中,这样当程序退出时,如果该codec

    • 于是,前面的字节流被解码为u"svool dliow!"这样一个unicode字符串
    • qDebug输出该字符串时,需要将其编码成字节流?如何编码?是由 QTextCodec::setCodecForLocale 控制的,默认编码为 system
    • 于是被编码成 "svool dliow!" 这样的字节流输出。

    插件

    前面自定义了一个codec的文件中多加一个类:

    #include <QTextCodecPlugin>
    #include <QTextCodec>
    
    class DbzhangCodecPlugin : public QTextCodecPlugin
    {
    public:
        DbzhangCodecPlugin() {}
    
        QList<QByteArray> names() const {return QList<QByteArray>()<<"dbzhang800";}
        QList<QByteArray> aliases() const {return QList<QByteArray>()<<"dbzhang-800";}
        QList<int> mibEnums() const {return QList<int>()<<2011;}
    
        QTextCodec *createForMib(int mib)
        {
            return mib == 2011 ? new DbzhangCodec : 0;
        }
    
        QTextCodec *createForName(const QByteArray & name)
        {
            if (name == "dbzhang800" || name == "dbzhang-800")
                return new DbzhangCodec;
            else
                return 0;
        }
    };
    
    Q_EXPORT_PLUGIN2(dbzhangcodec, DbzhangCodecPlugin)

    配合一个.pro 文件

    TARGET = dbzhangcodec
    TEMPLATE  = lib
    CONFIG    += plugin
    SOURCES += codecplugin.cpp

    然后将生成的动态库放入可执行程序目录下的codecs子目录下。

    此时,我们在程序中即可直接使用

        QTextCodec * 

    setCodecFor****

    这3个东西到底是做什么呢?

    QTextCodec::setCodecForCStrings(textc);
    QTextCodec::setCodecForTr(textc);
    QTextCodec::setCodecForLocale(textc);

    3个很简单的东西。字节流 <==> 字符串

    setCodecForCStrings

     

    void QTextCodec::setCodecForCStrings ( QTextCodec * codec used by QString to convert to and from const char * and QByteArrays. If the QString 与中文问题 我们介绍过这个东西。它将影响QString中
    • QString ( const char * str )
    • QString ( const QByteArray & ba )

    • QString & append ( const QByteArray & ba )

    • QString & append ( const char * str )

    • bool operator!= ( const QByteArray & other ) const

    • bool operator!= ( const char * other ) const
    • QString & operator= ( const QByteArray & ba )

    • QString & operator= ( const char * str )

    • QString fromAscii ( const char * str, int size = -1 )
    • QString fromAscii ( const char * str, int size = -1 )
    • ...

    等和字节流(QByteArray或char*)相关但有没有像fromUtf8等那样指定明确编码的成员函数。

    以及QByteArray类中涉及unicode字符串的那些成员函数

    • QByteArray & append ( const QString & str )

    • int indexOf ( const QString & str, int from = 0 ) const

    • bool operator< ( const QString & str ) const

    • ...

    setCodecForTr

     

    void QTextCodec::setCodecForTr ( QTextCodec * c ) [static]
    
    Sets the Qt中translate、tr关系 与中文问题 一文中我们过提到了一个问题。

    当我们使用

    QString QObject::tr ( const char * sourceText, const char * disambiguation = 0, int n = -1 ) [static]

    这种函数时,需要将 sourceText 这个字节流转换成一个QString字符串。

    如果我们已经加载了翻译文件,那么Qt将把该字节流作为一个key去查找相应的翻译好的字符串。

    如果没有加载翻译文件呢?Qt将需要某个setCodecForLocale

     

    void QTextCodec::setCodecForLocale ( QTextCodec * c ) [static]
    
    Set the codec is reset to the default.
    
    This might be needed for some applications that want to use their own mechanism for setting the locale.

    这个应该没什么好说的,在绝大多数情况下,我们在代码中应该都用不到这个函数(默认的system应该比我们所能设置的要好)。

    • 当我们从程序的命令行读取参数时int main(int argc, char *argv[])

    • 当我们从往控制台输出内容时qDebug()<<QString(...)

    • 使用 QString::fromLocal8Bit() 与 QString::toLocal8Bit()
    • ...
  • 相关阅读:
    java 运算符的优先级比较
    Java String类和StringBuffer类的区别
    Java 并发编程
    java构造函数和初始化
    Java 动态绑定
    Java day3
    Java day2
    Java day1
    计算机系统原理之程序是怎么运行的 【转】
    MemberCached 学习上【转】
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/5599630.html
Copyright © 2011-2022 走看看