分享

Qt QString 中文 char* UTF-8 QByteArray QTextCodec unicode gb2312 GBK 乱码与转码问题

 guitarhua 2012-05-11

Qt QString 中文 char* UTF-8 QByteArray QTextCodec unicode gb2312 GBK 乱码与转码问题

分类: linux 使用 175人阅读 评论(0) 收藏 举报

代码如下:如果不不设全局的字符集是utf-8,那么网上一般的方法是可以转的。如下程序中 #define DD 1的情况下;但是如果设置了全局的utf-8,再用以前的方法:

QByteArray ba=aaa.toLatin1();
const char *c_str = ba.data();
PS:c_str所指向的内存单元,如果你想长时间使用你应该复制出来,要不可能过数行代码后,你再读你的数据,c_str所指向的内存单元就不是你以前读的内容了。函数返回的指针临时变量,不能长时间使用!!!!!!!
具体代理在本贴最后补充出来:

等网上类似的方法,都会出现转代汉字不成功,但能转代ASICC码的情况。汉字都成了问号的ASICC码63。这是因为没有用对方法没有用转换utf-8码的方法。

转码是件很复杂的事。

#include <QtGui/QApplication>
#include<QTextCodec>
#include<QFont>
#include<QtGui>
#include <QByteArray>
#define DD 0
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    #if DD
            //没有设置全局的是utf-8字符
    #else
    QTextCodec *codec = QTextCodec::codecForName("UTF-8");
    QTextCodec::setCodecForLocale(codec);
    QTextCodec::setCodecForCStrings(codec);
    QTextCodec::setCodecForTr(codec);
    QFont font;
    font.setFamily(("WenQuanYi Zen Hei"));
    font.setPointSize(12);
    app.setFont(font);
    app.setFont(font);
    #endif
    QString aaa= "你好a1234";
    QString bbb="哈哈afaf394的AAA";
    #if DD
    QByteArray ba=aaa.toLatin1();
    const char *c_str = ba.data();
    printf("c_str:%s:size=%d\n",c_str,strlen(c_str));
    char *p;
    p=(char *)c_str;
    printf("p=%d\n",*p);
    p++;
    printf("p=%d\n",*p);
    QString ddd(c_str);
    qDebug()<<ddd;
    #else
    char *ad = aaa.toUtf8().data();
    char *bb=   bbb.toUtf8().data();
     printf("ad=%s,size=%d\n",ad,strlen(ad));
     printf("df=%s,size=%d\n",bb,strlen(bb));
    #endif
    QPushButton ccc("AWQ WQ wq 你了");
    ccc.show();
    return app.exec();
}

以下是在网上找的,感觉很好,可以一块理解:

这个好像就是用几种不同的字符,但不会出错,不像我们一种都搞不定

http://hi.baidu.com/codeworkman/blog/item/5c0d7516c5c03215c83d6dcc.html

Qt QString 中文 char* UTF-8 QByteArray QTextCodec unicode gb2312 GBK

#include <QFile>
#include <QFileDialog>
#include <QTextCodec>
#include <QByteArray>

void MainWindow::on_pushButton_clicked()
{    
    /*
      只有8位编码的才需要tr, unicode不要tr
      gb2312是GBK的子集,通常设成哪个都一样的
      所谓的QString转char*,结果并不相同,根据编码格式不同而不同
      QString转unicode,不用转,QString本身就是unicode
      QString的根本是QChar数组,但不是以0结尾,有大小,QChar的根本是ushot
      Qt中unicode声明:可以用wchar_t,也可以用ushot,没有WCHAR
      QByteArray可以理解为char类型的动态数组,有大小,不是以\0结尾
    */

    /*
        ui创建1个列表框QListWidget,和1个按钮即可

        用windows记事本分别创建4种文件,本例可直接打开
        ANSI:没有文件头,2字节/汉字,1字节/英文
        UTF-8:文件头[0xEF,0xBB,0xBF],3字节/汉字,1字节/英文
        Unicode:文件头[0xFF,0xFE],2字节/汉字,2字节/英文
        Unicode big endian :文件头[0xFE,0xFF],同Unicode,字节序相反

        QString转char*的规则同上;

    */

    /*
    QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
    QTextCodec::setCodecForTr(QTextCodec::codecForName("gb2312"));
    QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));

    如下使用想要得到正确结果必须使用类似以上的语句
    str = tr("显示中文");

    但以下这个可以直接使用
    strText = QString::fromLocal8Bit("显示中文");
    */

    ui->list->addItem(QString::fromLocal8Bit("--------显示中文----------"));

    QString strFileName = QFileDialog::getOpenFileName(this, tr("OpenFile"), ".", tr("Image Files(*.*)"));
    if(strFileName.length() == 0)
    {
        ui->list->addItem(tr("You didn't select any files."));
        return;
    }

    // 打开文件
    QFile *pFile = new QFile(strFileName);
    if (!pFile->open(QFile::ReadOnly))
    {
        ui->list->addItem(tr("open file fail %1: %2.").arg(strFileName).arg(pFile->errorString()));
        return;
    }
    ui->list->addItem(tr("open file ok %1").arg(strFileName));

    // 读文件
    qint64 fileSize = pFile->size();
    ui->list->addItem(tr("size = %1").arg(fileSize));
    char *pBuf = new char[fileSize];
    pFile->read(pBuf, fileSize);
    pFile->close();

    if(fileSize < 4)
    {
         ui->list->addItem(tr("fileSize < 4"));
         return;
    }

    QString strText;
    uchar *p = (uchar*)pBuf;


    if(p[0] == 0xEF && p[1] == 0xBB && p[2] == 0xBF)// UTF-8
    {
        ui->list->addItem(tr("UTF-8"));
        strText = QString::fromUtf8(pBuf + 3, fileSize - 3);
    }
    else if(p[0] == 0xFF && p[1] == 0xFE)// Unicode
    {
        ui->list->addItem(tr("Unicode"));
        strText = QString::fromWCharArray((wchar_t*)(pBuf + 2), (fileSize - 2) / 2);
    }
    else if(p[0] == 0xFE && p[1] == 0xFF)// Unicode big endian
    {
        ui->list->addItem(tr("Unicode big endian"));
        uchar uc = 0;
        for(int i = 3; i < fileSize; i += 2)
        {
            uc = p[i];
            p[i] = p[i - 1];
            p[i - 1] = uc;
        }
        strText = QString::fromWCharArray((wchar_t*)(pBuf + 2), (fileSize - 2) / 2);
    }
    else    //ANSI
    {       

        ui->list->addItem(tr("ANSI"));
        strText = QString::fromLocal8Bit(pBuf, fileSize);
    }

    ui->list->addItem(strText);

    QString strMsg, strTmp;

    //unicode
    strMsg = tr("unicode: ");
    QChar *pData = strText.data();
    for(int i = 0; i < strText.size(); i++)
    {
        strTmp = tr("0x%1, ").arg(QString::number(pData[i].unicode(), 16).toUpper());
        strMsg += strTmp;
    }
    ui->list->addItem(strMsg);


    // gb2312
    strMsg = tr("gb2312:  ");
    QByteArray ary1 = strText.toLocal8Bit();
    uchar *puchar = (uchar*)ary1.data();
    for(int i = 0; i < ary1.size(); i++)
    {
        strTmp = tr("0x%1, ").arg(QString::number(puchar[i], 16).toUpper());
        strMsg += strTmp;
    }
    ui->list->addItem(strMsg);

    // uft8
    strMsg = tr("utf-8:   ");
    ary1 = strText.toUtf8();
    puchar = (uchar*)ary1.data();
    for(int i = 0; i < ary1.size(); i++)
    {
        strTmp = tr("0x%1, ").arg(QString::number(puchar[i], 16).toUpper());
        strMsg += strTmp;
    }
    ui->list->addItem(strMsg);

    ui->list->addItem(tr(" "));
}

以下这个我认为是中文字符的深入理解吧:

http://hi.baidu.com/cyclone/blog/item/9d7293130e5a498d6538dbf1.html

QString 与中文问题
2010-07-11 17:04
(更新:本文的姊妹篇 Qt中translate、tr关系 与中文问题 )

首先呢,声明一下,QString 是不存在中文支持问题的,很多人遇到问题,并不是本身 QString 的问题,而是没有将自己希望的字符串正确赋给QString。

很简单的问题,
"我是中文"这样写的时候,它是传统的 char 类型的窄字符串,我们需要的只不过是通过某种方式告诉QString 这四个汉字采用的那种编码。而问题一般都出在很多用户对自己当前的编码没太多概念,

于是

一个简 单的 Qt 程序

下面这个小程序,估计大家会感到比较亲切。似乎有相当多的中文用户尝试写过这样的代码:

#include <QtGui/QApplication>
#include <QtGui/QLabel>

int main(int argc, char **argv)
{
QApplication app(argc, argv);
QString a= "我是汉字";
QLabel label(a);
label.show();
return app.exec();
}

编码,保存,编译,运行,一切都很顺利,可是结果呢:

  • 多数用户看到

    其他用户看到

    òê?oo×?

    ‘??ˉ?±‰? —

出乎意料,界面上中文没显示出来,出现了不认识字符。 于是开始用搜索引擎搜索,开始上论坛发帖或抱怨

最后被告知,下面的语句之一可以解决问题:

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

两条指令挨个一试,确实可以解决(多数用户是第一条,其他用户是第二条)。那么,为什么会这样呢?

两种乱码什么时候出现

对这个问题,我想大家可能都有话说。在继续之前,我们先列个表,看看两种乱码分别在那种情况下出现:

我们只列举大家最常用的3个编译器(微软VS的中的cl,Mingw中的g++,Linux下的g++),源代码分别采用 GBK 和 不带BOM的UTF-8  以及 带BOM的UTF-8 这3中编码进行保存。

  • 源代码的编码

    编译器

    结果

     

    GBK

    cl

    1

    *

    mingw-g++

    1

    *

    g++

    1

     

    UTF-8(不带BOM)

    cl

    2

     

    mingw-g++

    2

     

    g++

    2

    *

    UTF-8(带BOM)

    cl

    1

     

    mingw-g++

    2

     

    g++

    编译失败

     

采用3种不同编码保存的源代码文件,分别用3种不同的编译器编译,形成9种组合,除掉一种不能工作的情况,两种乱码出现的情况各占一半。

从中我们也可以看出,乱码和操作系统原本是没有关系的。但我们在 Windows 一般用的GBK,linux一般用的是不带BOM的UTF-8。如果我们只考虑带*的情况,也可以说两种乱码和系统有关。

QString 为什么会乱码呢

真的是 QString 乱码了吗?我们可以问问自己,我们抱怨的对象是不是搞错了?

继续之前,先明确几个概念:

明确概念0:

  • "我是汉字" 是C语言中的字符串,它是char型的窄字符串。上面的例子可写为
const char * str = "我是汉字";
QString a= str;

char str[] = "我是汉字";
QString a= str;

明确概念1:

  • 源文件是有编码的,但是这种纯文本文件却不会记录自己采用的编码

这个是问题的根源,不妨做个试验,将前面的源代码保存成GBK编码,用16进制编辑器能看到引号内是ce d2 ca c7 ba ba d7 d6这样8个字节。

现在将该文件拷贝到正体(繁体)中文的Windows中,用记事本打开会什么样子呢?

...
QString a= "扂岆犖趼";
QLabel label(a);
label.show();
...

那么放到欧美人的Windows系统中,再用记事本打开呢?

...
QString a= "òê?oo×?";
QLabel label(a);
label.show();
...

同一个文件,未做任何修改,但其中的8个字节ce d2 ca c7 ba ba d7 d6,对用GBK的大陆人,用BIG5的港澳台同胞,以及用Latin-1的欧洲人看来,看到的却是完全不同的文字。

明确概念2:

  • 如同我们都了解的'A'与'\x41'等价一样。

GBK编码下的

const char * str = "我是汉字"

等价于

const char * str = "\xce\xd2\xca\xc7\xba\xba\xd7\xd6";

当用UTF-8编码时,等价于

const char * str = "\xe6\x88\x91\xe6\x98\xaf\xe6\xb1\x89\xe5\xad\x97";

注意:这个说法不全对,比如保存成带BOM的UTF-8,用cl编译器时,汉字本身是UTF-8编码,但程序内保存时却是对应的GBK编码。

明确概念3:

  • QString 内部采用的是Unicode。

QString内部采用的是 Unicode,它可以同时存放GBK中的字符"我是汉字",BIG5中的字符"扂岆犖趼" 以及Latin-1中的字符"?òê?oo×?"。

一个问题是,源代码中的这8个字节"\xce\xd2\xca\xc7\xba\xba\xd7\xd6",该怎么转换成Unicode并存到 QString 内?按照GBK、BIG5、Latin-1还是其他方式...

在你不告诉它的情况下,它默认选择了Latin-1,于是8个字符"?òê?oo×?"的unicode码被存进了QString中。最终,8个Latin字符出现在你期盼看到4中文字符的地方,所谓的乱码出现了

QString 工作方式

const char * str = "我是汉字";
QString a= str;

其实很简单的一个问题,当你需要从窄字符串 char* 转成Unicode的QString字符串的,你需要告诉QString你的这串char* 中究竟是什么编码?GBK、BIG5、Latin-1

理想情况就是:将char* 传给QString时,同时告诉QString自己的编码是什么:

就像下面的函数一样,QString的成员函数知道按照何种编码来处理 C 字符串

QString QString::fromAscii ( const char * str, int size = -1 )
QString QString::fromLatin1 ( const char * str, int size = -1 )
QString QString::fromLocal8Bit ( const char * str, int size = -1 )
QString QString::fromUtf8 ( const char * str, int size = -1 )

单QString 只提供了这几个成员函数,远远满足不了大家的需求,比如,在简体中文Windows下,local8Bit是GBK,可是有一个char串是 BIG5 或 Latin-2怎么办?

那就动用强大的QTextCodec吧,首先QTextCodec肯定知道自己所负责的编码的,然后你把一个char串送给它,它就能正确将其转成Unicode了。

QString QTextCodec::toUnicode ( const char * chars ) const

可是这个调用太麻烦了,我就想直接

QString a= str;

QString a(str);

这样用怎么办?

这样一来肯定没办法同时告诉 QString 你的str是何种编码了,只能通过其他方式了。这也就是开头提到的

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GBK"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

设置QString默认采用的编码。而究竟采用哪一个,一般来说就是源代码是GBK,就用GBK,源代码是UTF-8就用UTF-8。但有一个例外,如果你保存成了带BOM的UTF-8而且用的微软的cl编译器,此时仍是GBK。



最后是简单的编程上的类型转换,就是具体方法的应用:


http://blog.csdn.net/ghostyu/article/details/6998640

qt学习笔记(三) QString char int之间的转换


char * 与 const char *的转换
char *ch1="hello11";
const char *ch2="hello22";
ch2 = ch1;//不报错,但有警告
ch1 = (char *)ch2;

char 转换为 QString
其实方法有很多中,我用的是:
char a='b';
QString str;
str=QString(a);


QString 转换为 char
方法也用很多中
QString str="abc";
char *ch;
ch = str.toLatin1.data();


QByteArray 转换为 char *
char *ch;//不要定义成ch[n];
QByteArray byte;
ch = byte.data();


char * 转换为 QByteArray
char *ch;
QByteArray byte;
byte = QByteArray(ch);


QString 转换为 QByteArray
QByteArray byte;
QString string;
byte = string.toAscii();




QByteArray 转换为 QString
QByteArray byte;
QString string;
string = QString(byte);
这里再对这俩中类型的输出总结一下:
qDebug()<<"print";
qDebug()<<tr("print");
qDebug()<<ch;(ch 为char类型)
qDebug()<<tr(ch);
qDebug()<<byteArray;(byteArray是QByteArray类型)
qDebug()<<tr(byteArray);
qDebug()<<str;(str 为Qstring类型)
但是qDebug()<<tr(str);是不可以的,要想用tr()函数输出QString类型的字符则要如下:
qDebug()<<tr(str.toLatin1);


int 转 QString
int a=10;
QString b;
b=QString::number(a)


QString 转int
QString a="120"
int b;
b=a.toInt()
char * 与 const char *的转换
char *ch1="hello11";
const char *ch2="hello22";
ch2 = ch1;//不报错,但有警告
ch1 = (char *)ch2;


char 转换为 QString
其实方法有很多中,我用的是:
char a='b';
QString str;
str=QString(a);


QString 转换为 char
方法也用很多中
QString str="abc";
char *ch;
ch = str.toLatin1.data();


QByteArray 转换为 char *
char *ch;//不要定义成ch[n];
QByteArray byte;
ch = byte.data();


char * 转换为 QByteArray
char *ch;
QByteArray byte;
byte = QByteArray(ch);


QString 转换为 QByteArray
QByteArray byte;
QString string;
byte = string.toAscii();




QByteArray 转换为 QString
QByteArray byte;
QString string;
string = QString(byte);
这里再对这俩中类型的输出总结一下:
qDebug()<<"print";
qDebug()<<tr("print");
qDebug()<<ch;(ch 为char类型)
qDebug()<<tr(ch);
qDebug()<<byteArray;(byteArray是QByteArray类型)
qDebug()<<tr(byteArray);
qDebug()<<str;(str 为Qstring类型)
但是qDebug()<<tr(str);是不可以的,要想用tr()函数输出QString类型的字符则要如下:
qDebug()<<tr(str.toLatin1);


int 转 QString
int a=10;
QString b;
b=QString::number(a)


QString 转int
QString a="120"
int b;
b=a.toInt()
另一个


1 QString --> string
QString.toStdString();
2 string --> QString
QString::fromStdString(string)
3 QString --->int,double,char *
QString::toInt()
QString::toDouble()
QString.toStdString().c_str();
4 int double char* --->string
可以采用<sstream>里的stringstream
以int 为例,int a = 3;
stringstream ss;
string strInt;
ss<<a;
ss>>strInt;





开始时所 说的病例程序:

背景都是红色的代码作用是相同的,但打出的结果不一样,后面一个出不了正确的信息,这就是为什么开始说的临时变量不能长时间使用

#include <QtGui/QApplication>
#include "widget.h"
#include<QTextCodec>
#include<QFont>
#include"database.h"
#include<QtGui>
#include<QPushButton>
#include <QByteArray>
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QTextCodec *codec = QTextCodec::codecForName("UTF-8");
    QTextCodec::setCodecForLocale(codec);
    QTextCodec::setCodecForCStrings(codec);
    QTextCodec::setCodecForTr(codec);
    QFont font;
    font.setFamily(("WenQuanYi Zen Hei"));
    font.setPointSize(12);
    app.setFont(font);
    app.setFont(font);
    //if(!createConnection())
      //  return 1 ;
    QString aaa= "灯开kl";
       QString bbb="机顶盒的控制字";
       QString ccc = "频道加" ;
       #if 0
       QByteArray ba=aaa.toLatin1();
       const char *c_str = ba.data();
       printf("c_str:%s:size=%d\n",c_str,strlen(c_str));
       char *p;
       p=(char *)c_str;
       printf("p=%d\n",*p);
       p++;
       printf("p=%d\n",*p);
       QString ddd(c_str);
       qDebug()<<ddd;
       #else
       char *ad = aaa.toUtf8().data();
       char *bb=  bbb.toUtf8().data();
       char *cc = ccc.toUtf8().data();
       char a1[100],a2[100],a3[100];
       memset(a1, 0, sizeof(a1));
       memset(a2, 0, sizeof(a2));
       memset(a3, 0, sizeof(a3));
       strncpy(a1, ad, strlen(ad));
       strncpy(a2, bb, strlen(bb));
       strncpy(a3, cc, strlen(cc));
        printf("ad=%s,size=%d\n",ad,strlen(ad));
        printf("df=%s,size=%d\n",bb,strlen(bb));
        printf("cd=%s,size=%d\n",cc,strlen(cc)) ;
        printf("a1=%s,size=%d\n",a1,strlen(a1));
        printf("a2=%s,size=%d\n",a2,strlen(a2));
        printf("a3=%s,size=%d\n",a3,strlen(a3));
        int len1 = strlen(ad) ;
        int len2 = strlen(bb) ;
        //qDebug() << ad << len1 << bb << len2 ;
       #endif
       QPushButton cccc("AWQ WQ wq 制热");
       cccc.show();
    sqlite3 *db;
    char *zErrMsg ;
    sqlite3_stmt *stmt;
    int Codec_Id = 1;
    if((sqlite3_open("room.db",&db))!=0){
        qDebug() << "sqlite3 open is false";
    }
    else{
        qDebug() <<  "sqlite3 open is OK";
    }
   char sql3[100];
    int room_Id = 1 ;
    int Device_Id = 1 ;
    int Device_Type = 11 ;
    int Control_Bty = 11 ;
    int Control_Status = 1  ;
    int ncols ,rc ;
    sprintf(sql3,"insert into Codec values(%d,%d,%d,%d,%d,%d,'%s','%s','%s');",Codec_Id,room_Id,Device_Id,Device_Type,Control_Bty,Control_Status,a1,a2,a3);
    printf("sql3=%s\nlen=%d\n",sql3,strlen(sql3));
    sqlite3_exec(db,sql3,NULL,NULL,&zErrMsg);
    printf("zErrMsg = %s \n", zErrMsg);     //检查插入的数据有没有问题
    memset(sql3,0,sizeof(sql3)) ;
    sprintf(sql3,"select * from Codec ;") ;
    int nrow = 0, ncolumn = 0;
    char **azResult; //二维数组存放结果
    sqlite3_get_table(db, sql3,&azResult , &nrow , &ncolumn , &zErrMsg );
    int i = 0 ;
    //printf("size=%d\n",strlen(azResult));
     printf( "row:%d column=%d \n" , nrow , ncolumn );
     printf( "\nThe result of querying is : \n" );
     for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )
      printf( "size=%d    azResult[%d] = %s\n",strlen(azResult[i]), i , azResult[i] );
     //释放掉  azResult 的内存空间
     sqlite3_free_table( azResult );
    sqlite3_prepare(db,sql3,strlen(sql3),&stmt,NULL);
        ncols = sqlite3_column_count(stmt);
        rc = sqlite3_step(stmt);
   char *name ;
        while(rc == SQLITE_ROW){
                name = (char *)sqlite3_column_text(stmt,0);
                fprintf(stderr,"Row:Codec_id=%s,%d\n",name,strlen(name));  //L_id 表示是灯的设备表的id
                rc = sqlite3_step(stmt);
                }
    sqlite3_close(db);
    printf("ad=%s,size=%d\n",ad,strlen(ad));
    printf("df=%s,size=%d\n",bb,strlen(bb));
    printf("cd=%s,size=%d\n",cc,strlen(cc)) ;
    return app.exec();
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多