何处开始呢?

一旦在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乱谈相关推荐

  1. qmake 乱乱乱谈(一)

    不想太深入地去看qmake,可是,左等,右等,总不见Qt新的构建系统有什么新消息.还是整理一下qmake吧,由于没什么主题,还不知道本文最终会乱到什么程度. 注:你可能会对下面的内容感兴趣. 浅谈 q ...

  2. qmake 乱乱乱谈(二)

    接前面qmake 乱乱乱谈(一),继续看看qmake. 暂定主题:qmake之命令行参数及qmake启动时加载了什么东西,或许可以借此学习一下qmake是处理命令行参数的方法 命令行参数 运行 qma ...

  3. qmake 乱乱乱谈(三)

    接前面的qmake 乱乱乱谈(一)以及qmake 乱乱乱谈(二),本文看看qmake中的函数(Manual中有的就不重复了). 函数分两种: 内置函数 (qmake Manual中列出的属于此类) 自 ...

  4. [置顶]       jQuery乱谈(六)

    接上一篇:jQuery乱谈(五),今天分析removeClass().removeProp().toggleClass().val().  removeClass(): /** * removeCla ...

  5. 雷兽的数据库CAP乱谈之(一)阐述

    雷兽的数据库CAP乱谈之(一)阐述 今天有人问我cap,找了https://my.oschina.net/lilw/blog/169776这片文字, 下面是cap那篇文字的解释: 所谓CAP理论,即: ...

  6. 乱谈互联网产品开发(二)

    潜意识里,我一直认为网站开发是没有技术含量的.由于我一直在软件公司做组件,底层等相关技术的研究和开发,只要看到跟界面相关的系统就会没工作激情.对"网页开发"之类的东西就更心存鄙夷. ...

  7. centos 计算器_计算初学者进行服务器centos 7.6系统及orca、xtb、gaussian 16软件的安装乱谈...

    本帖最后由 欢乐多 于 2020-8-18 10:37 编辑 自己动手丰衣足食--计算初学者进行服务器centos 7.6系统及orca.xtb.gaussian 16软件的安装乱谈 经过一夜苦战通宵 ...

  8. 菜鸟的AI安全乱谈(2)—通过模型再训练留后门

    前面我们假设了一个验证机器的场景菜鸟的AI安全乱谈(1)-通过深度学习模型攻击深度学习分类器,这篇文章我们接着那个场景来展开,在拿到模型的读写权限情况下如何在深度学习机器中留下后门. 那么,如何在深度 ...

  9. 转载:编剧技巧思路乱谈

    http://hgs521.com/html/dongmanjiaocheng/juben/20080130/41.html 编剧技巧思路乱谈 经常有朋友感到没有故事好写,或者在一个故事上苦苦思索,最 ...

最新文章

  1. 4月《程序员》上我讲HTML5的文章---激动人心的HTML5之美
  2. java多线程发牌 一个发牌 三个玩家_JAVA代码之斗地主发牌
  3. Creating my own systemd service files on Fedora 16(x86_64)
  4. C# .NET Web API 如何自訂 ModelBinder
  5. 素数环 与 算法 全排列
  6. 安卓开发笔记(二十二):读取本地(内置)html文件并实现和Javascript交互
  7. 创立三年,广受好评:如何评价 ApacheCN ?
  8. 网站策划:如何书写网站的商业计划书
  9. 【poj2096】Collecting Bugs 期望dp
  10. R语言数据异常值处理
  11. VMware没有未桥接的主机网络适配器,VMware bridge protocol服务卸载不掉
  12. iOS文字颜色渐变透明
  13. java 电子栅栏,Java Exchanger栅栏
  14. sql语句中大于号小于号的处理
  15. Rasterio入门
  16. 国内可用的 ChatGPT
  17. 金沙滩51单片机74HC138 三八译码器的应用
  18. 【C语言】sizeof操作符详解
  19. 硬件知识:独立显卡和集成显卡的区别
  20. 齐二TK6916/20/26/32系列数控落地铣镗床简介7

热门文章

  1. 编写Python语言,使用循环求解1到100之间数的偶数和
  2. (一)操作系统的基本概念
  3. SuperZero gero同步区块进度可视化
  4. Android Weekly - 42 : 打铁还需自身硬
  5. Ubuntu server 设置root密码
  6. HMC 命令行 查看小型机信息命令大全
  7. python--mysql--驱动简介和使用
  8. 微信小程序iOS使用input输入时placeholder及输入内容消失或隐藏
  9. 达人评测 n5095和i3 10110u选哪个
  10. 2022美亚杯第八届中国电子数据取证大赛-个人赛write up详解,软件就用弘连和美亚,尽量写的细致一点。建议入门看,仅为了解题,没有专业精神。专业选手去看后面推荐的两篇解析,都是大佬。