Qt之QTextCodec乱谈

转载 2012年03月27日 14:12:36

何处开始呢?

一旦在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 究竟是做了什么,我们不妨先定义自己的一个codec看看:

自定义QTextCodec

  • 定义一个类似latin1的单字节的字符集
    • 共 0~255 这256个码位
    • 与latin1相比,只不过是a-z和A-Z都反了一下序
  • 比如,对与字节流"\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21"
    • 按照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到字节流的转换。

使用举例

定义了一个自定义的codec,那么如何使用呢?

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尚未销毁,则会被清理。

这个例子中涉及两处字符串和字节流的转换。

  • "hello world!" 是字节流,等价于 "\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21"
  • 将QString和字节流的默认转换编码设置为我们自定义的codec
  • 于是,前面的字节流被解码为u"svool dliow!"这样一个unicode字符串
  • qDebug输出该字符串时,需要将其编码成字节流?如何编码?是由 QTextCodec::setCodecForLocale 控制的,默认编码为 system
  • 于是被编码成 "svool dliow!" 这样的字节流输出。

插件

前面自定义了一个codec,尽管用起来没问题,好像不太正规哈。一般不是要弄个插件出来,然后放到可执行程序所在目录下的codecs子目录下,让程序来自动识别么?

恩,稍微多做一点工作,在前面定义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 * codec = QTextCodec::codecForName("dbzhang800");

setCodecFor****

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

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

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

setCodecForCStrings

void QTextCodec::setCodecForCStrings ( QTextCodec * codec ) [static]

//Sets the codec used by QString to convert to and from const char * and QByteArrays. If the codec is 0 (the default), QString assumes Latin-1.

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 codec used by QObject::tr() on its argument to c. If c is 0 (the default), tr() assumes Latin-1.

 Qt中translate、tr关系 与中文问题 一文中我们过提到了一个问题。

当我们使用

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

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

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

如果没有加载翻译文件呢?Qt将需要某个codec将该字节流解码成unicode字符串。

setCodecForLocale

void QTextCodec::setCodecForLocale ( QTextCodec * c ) [static]

//Set the codec to c; this will be returned by codecForLocale(). If c is a null pointer, 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()
  • ...

Qt之QTextCodec乱谈

何处开始呢? 一旦在Qt程序中出现latin1字符集以外的字符,几乎大家无一例外的会用到 QTextCodec。 而不少网友不分青红皂白,一旦用到中文,就同时使用下面3条指令(其中te...
  • oMingZi12345678
  • oMingZi12345678
  • 2013年08月23日 13:29
  • 912

Qt5 取消了QTextCodec::setCodecForTr()和QTextCodec::setCodecForCString()这两个函数。

Qt5 取消了QTextCodec::setCodecForTr()和QTextCodec::setCodecForCString()这两个函数。
  • rl529014
  • rl529014
  • 2016年01月17日 19:03
  • 965

Qt 汉字显示问题//QTextCodec::setCodecForTr(QTextCodec::codecForName("gb18030"));

Qt控件中含有汉字的话,需要
  • my_friend_ship
  • my_friend_ship
  • 2014年10月13日 15:11
  • 1240

[Bug]QT解决中文乱码(tr的使用 | QTextCodec)

QT代码中使用了中文,会出现乱码,主要是未设置code类型。 修改mian函数所在的cpp文件: 一、添加include #include 二、main函数中添加代码 ...
  • ymc0329
  • ymc0329
  • 2012年02月22日 19:30
  • 5167

Qt解决中文乱码(tr的使用QTextCodec)

方法一: 1,在main.cpp中添加include #include 2,main函数中添加代码: int main(int argc, char **argv)  { ............
  • Xiong70
  • Xiong70
  • 2016年10月27日 20:57
  • 1800

Qt读取ANSI格式文件——利用QTextCodec将其他编码格式转换为Unicode格式

Qt使用Unicode来表示字符串。但是通常需要打开
  • desert187
  • desert187
  • 2014年10月08日 16:50
  • 1939

qt 出现 error: 'setCodecForTr' is not a member of 'QTextCodec'等错误的请进..

qt版本更新越来越块,更新的同时也有许多改动,坑了不少人.... 出现错误: 请直接查看main函数里面; 这时候只需要注释这两行就行; 出错原因:     Qt5以前很多人习惯用下面这三...
  • u012907149
  • u012907149
  • 2016年12月26日 02:24
  • 3653

Qt的QTextCodec用法(渣翻译)

先贴上官网原文的地址: http://doc.qt.io/qt-5/qtextcodec.html ,也可以从creator的帮助文档中找到   仅供学习,如有错误欢迎指出~  ...
  • qq_23948025
  • qq_23948025
  • 2015年05月05日 11:50
  • 1609

QString乱谈(2)

长期以来,很多人都清楚,一旦C++源码中直接使用了中文,这样的源码想要跨平台(I18N)会非常困难。 随着: Windows下:MSVC2010成为主流Linux下:GCC升级到4.6 C+...
  • dbzhang800
  • dbzhang800
  • 2012年05月07日 03:02
  • 21709

QTextCodec 之 QT 编码转换

// 直接使用汉字时, 可以使用以下宏 // GB2312, GBK, GB18030, 字符集范围依次扩大, 并向前兼容 // 目前不支持 GB18030, 使用 GBK 代替 // GBX 将ch...
  • wwang196988
  • wwang196988
  • 2011年09月12日 16:32
  • 2294
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Qt之QTextCodec乱谈
举报原因:
原因补充:

(最多只允许输入30个字)