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 究竟是做了什么,我们不妨先定义自己的一个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乱谈相关推荐
- qmake 乱乱乱谈(一)
不想太深入地去看qmake,可是,左等,右等,总不见Qt新的构建系统有什么新消息.还是整理一下qmake吧,由于没什么主题,还不知道本文最终会乱到什么程度. 注:你可能会对下面的内容感兴趣. 浅谈 q ...
- qmake 乱乱乱谈(二)
接前面qmake 乱乱乱谈(一),继续看看qmake. 暂定主题:qmake之命令行参数及qmake启动时加载了什么东西,或许可以借此学习一下qmake是处理命令行参数的方法 命令行参数 运行 qma ...
- qmake 乱乱乱谈(三)
接前面的qmake 乱乱乱谈(一)以及qmake 乱乱乱谈(二),本文看看qmake中的函数(Manual中有的就不重复了). 函数分两种: 内置函数 (qmake Manual中列出的属于此类) 自 ...
- [置顶] jQuery乱谈(六)
接上一篇:jQuery乱谈(五),今天分析removeClass().removeProp().toggleClass().val(). removeClass(): /** * removeCla ...
- 雷兽的数据库CAP乱谈之(一)阐述
雷兽的数据库CAP乱谈之(一)阐述 今天有人问我cap,找了https://my.oschina.net/lilw/blog/169776这片文字, 下面是cap那篇文字的解释: 所谓CAP理论,即: ...
- 乱谈互联网产品开发(二)
潜意识里,我一直认为网站开发是没有技术含量的.由于我一直在软件公司做组件,底层等相关技术的研究和开发,只要看到跟界面相关的系统就会没工作激情.对"网页开发"之类的东西就更心存鄙夷. ...
- centos 计算器_计算初学者进行服务器centos 7.6系统及orca、xtb、gaussian 16软件的安装乱谈...
本帖最后由 欢乐多 于 2020-8-18 10:37 编辑 自己动手丰衣足食--计算初学者进行服务器centos 7.6系统及orca.xtb.gaussian 16软件的安装乱谈 经过一夜苦战通宵 ...
- 菜鸟的AI安全乱谈(2)—通过模型再训练留后门
前面我们假设了一个验证机器的场景菜鸟的AI安全乱谈(1)-通过深度学习模型攻击深度学习分类器,这篇文章我们接着那个场景来展开,在拿到模型的读写权限情况下如何在深度学习机器中留下后门. 那么,如何在深度 ...
- 转载:编剧技巧思路乱谈
http://hgs521.com/html/dongmanjiaocheng/juben/20080130/41.html 编剧技巧思路乱谈 经常有朋友感到没有故事好写,或者在一个故事上苦苦思索,最 ...
最新文章
- 4月《程序员》上我讲HTML5的文章---激动人心的HTML5之美
- java多线程发牌 一个发牌 三个玩家_JAVA代码之斗地主发牌
- Creating my own systemd service files on Fedora 16(x86_64)
- C# .NET Web API 如何自訂 ModelBinder
- 素数环 与 算法 全排列
- 安卓开发笔记(二十二):读取本地(内置)html文件并实现和Javascript交互
- 创立三年,广受好评:如何评价 ApacheCN ?
- 网站策划:如何书写网站的商业计划书
- 【poj2096】Collecting Bugs 期望dp
- R语言数据异常值处理
- VMware没有未桥接的主机网络适配器,VMware bridge protocol服务卸载不掉
- iOS文字颜色渐变透明
- java 电子栅栏,Java Exchanger栅栏
- sql语句中大于号小于号的处理
- Rasterio入门
- 国内可用的 ChatGPT
- 金沙滩51单片机74HC138 三八译码器的应用
- 【C语言】sizeof操作符详解
- 硬件知识:独立显卡和集成显卡的区别
- 齐二TK6916/20/26/32系列数控落地铣镗床简介7
热门文章
- 编写Python语言,使用循环求解1到100之间数的偶数和
- (一)操作系统的基本概念
- SuperZero gero同步区块进度可视化
- Android Weekly - 42 : 打铁还需自身硬
- Ubuntu server 设置root密码
- HMC 命令行 查看小型机信息命令大全
- python--mysql--驱动简介和使用
- 微信小程序iOS使用input输入时placeholder及输入内容消失或隐藏
- 达人评测 n5095和i3 10110u选哪个
- 2022美亚杯第八届中国电子数据取证大赛-个人赛write up详解,软件就用弘连和美亚,尽量写的细致一点。建议入门看,仅为了解题,没有专业精神。专业选手去看后面推荐的两篇解析,都是大佬。