如下在 Python2.6和PyQt4.4.4 for Python2,6環境下討論: python
Python中有兩種有關字符的類型:Python string object和Python Unicode object。主要使用Python string object進行數據輸入輸出。
PyQt中與之相對應的字符有關類型是:QByteArray和QString。主要使用QString操做數據。 shell
1. Python和PyQt中的類型對應 編程
注意是類型類似,不是相等。
須要先了解編碼:ascii、gb23十二、big5,這些是各國本身文字不一樣的編碼;unicode,國際通用編碼,就是窮盡這個世界上全部的文字,給 每一個文字編一個,又分utf-8方案--最常使用的128個英文字母用一個字節來表示,而中文使用三個字節來表示,utf-16方案--其中英文和中文都 使用兩個字節來表示,而其它字符采用四個字節,utf-32方案--全部的文字都用四個字節來表示。
unicode就可用來做爲各類獨立編碼如ascii、gb23十二、big5的轉換中介。
Python中gkb == gb2312。 網絡
1)Python string object能夠理解爲一個接一個字節(byte,8位)的字節組,至於表示什麼編碼,與表示文字有關,如:"python string","中文"。注意它是有不一樣編碼區分的!
PyQt中與之至關的是QByteArray,注意不是QString! app
A built-in string object (plain or Unicode) is a sequence of characters used to store and represent text-based information (plain strings are also sometimes used to store and represent arbitrary sequences of binary bytes). (摘自《Python in a NutShell》) ide
QByteArray can be used to store both raw bytes (including '0's) and traditional 8-bit '0'-terminated.(摘自《PyQt手冊》) 函數
2)Python Unicode object能夠理解爲固定使用utf-16編碼的字節組,其中英文和中文都使用兩個字節(16位)來表示,如:u"Python Unicode object"、u"中文"。
PyQt中與之對應的就是QString了。 ui
Unicode string literals have the same syntax as other string literals, with a u or U immediately before the leading quote. (摘自《Python in a NutShell》) 編碼
Qt also provides the QString class to store string data. It stores 16-bit Unicode characters, making it easy to store non-ASCII/non-Latin-1 characters in your application.(摘自《PyQt手冊》)
QString stores a string of 16-bit QChars, where each QChar corresponds one Unicode 4.0 character.(摘自《PyQt手冊》) spa
2. PyQt內部類型轉換
QString有 toAscii()、toUtf8()函數轉換爲QByteArray類型,(這個基本不用,由於不多直接用QByteArray類型)有 __init__ (self, QByteArray a)函數將QByteArray類型轉爲QString。
3. Python string object和Python Unicode object相互轉換
1)Python string object是原始編碼是有區分的,經過 decode('原始編碼') 函數解碼獲得通用utf16編碼即Python Unicode object。
>>>"python string".decode('ascii')
或者
>>>"python string".decode()
獲得 u"python string"
由於默認按ascii解碼。
>>>"中文".decode('gbk')
獲得 u"u4e2du6587" ,打印出來就是 中文 二字。(注意結果是2字節一組,共兩組,對應兩個漢字)
又:"python string".decode('gkb') ,即按漢字來解碼,也能夠獲得 u"python string",由於gbk編碼也支持英文字母;
可是"中文".decode('ascii') 即按ascii解碼是錯誤的,由於ascii編碼不支持漢字!
>>> "dfdf".decode()
u'dfdf'
>>> "dfdf".decode("ascii")
u'dfdf'
>>> "dfdf".decode("gbk")
u'dfdf'
>>> "中文".decode("gbk")
u'u4e2du6587'
>>>print "中文".decode("gbk")
中文
>>> "中文".decode("gb2312")
u'u4e2du6587'
>>> "中文".decode("ascii")
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd6 in position 0: ordinal not in range(128)
2)Python Unicode object原始編碼固定是utf16,經過 encode('目的編碼') 編碼來獲得Python string object。
>>>u"unicode string".encode()
或者
>>>u"unicode string".encode('ascii')
獲得
'unicode string',默認目的編碼爲ascii。
>>>u"中文".encode("gbk")
獲得'xd4xd0xcexc4',打印出來就是 中文。(注意結果是1字節一組,共4組)
>>> u"sdff".encode()
'sdff'
>>> u"sdff".encode('ascii')
'sdff'
>>> u"sdff".encode('gbk')
'sdff'
>>> u"sdff".encode('gb2312')
'sdff'
>>> u"中文".encode('gbk')
'xd6xd0xcexc4'
>>> print u"中文".encode('gbk')
中文
>>> u"中文".encode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordin
al not in range(128)
注意:執行>>> u"中文".encode('gbk')命令須要你的IDE支持gbk編碼,在官方shell下執行確定沒問題,但若是你的IDE好比PyWin中文輸入 異常,則可能報錯。
4. Python string object和Python Unicode object向QString的轉換。
Qt通常不直接操做QByteArray,只需關注Python string object和Python Unicode object向QString的轉換。
不少關於PyQt4的英文書籍說:PyQt函數須要QString參數的地方均可以直接用Python string object或者Python Unicode object,若是非要轉換能夠直接用QtCore.QString()構造。好比《GUI Programming with PyQt》,再如《PyQt手冊》:
Whenever PyQt expects a QString as a function argument, a Python string object or a Python Unicode object can be provided instead, and PyQt will do the necessary conversion automatically.
You may also manually convert Python string and Unicode objects to QString instances by using the QString constructor as demonstrated in the following code fragment:
qs1 = QtCore.QString("Converted Python string object")
qs2 = QtCore.QString(u"Converted Python Unicode object")
但惋惜這隻適用於英文 即ascii編碼,對於中文則行不通!
直接的 QString:
>>> QtCore.QString('中文')
PyQt4.QtCore.QString(u'xd6xd0xcexc4')
>>> print QtCore.QString('中文')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordin
al not in range(128)
>>>
>>> QtCore.QString(u'中文')
PyQt4.QtCore.QString(u'u4e2du6587')
>>> print QtCore.QString(u'中文')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordin
al not in range(128)
>>>
由於它們都是默認按ascii編碼轉換!
GUI編程:
能夠建立一個QTextEdit對象myTextEdit, 檢驗:
myTextEdit.append("中文")
或者
myTextEdit.append(u"中文")
或者
myTextEdit.append(QtCore.QString('中文'))
或者
myTextEdit.append(QtCore.QString(u'中文'))
你會發現顯示都是亂碼...由於它們都是默認按ascii編碼進行內部轉換獲得QString相應utf16編碼的。
解決方法是:
利用unicode()函數顯示指定gb2312編碼進行中文編碼轉換,轉換後的Python Unicode object則是能夠直接做爲QString參數代入用的:
>>> unicode('中文', 'gb2312', 'ignore')
u'u4e2du6587'
>>> print unicode('中文', 'gb2312', 'ignore')
中文
>>>
myTextEdit.append(unicode(' 中文', 'gb2312', 'ignore'))
#用以替代myTextEdit.append(u"中文")
或者畫蛇添足下:
myTextEdit.append(QtCore.QString(unicode('中文', 'gb2312', 'ignore')))
#用以替代myTextEdit.append(QtCore.QString(u'中文'))
5. QString向Python string object和Python Unicode object的轉換。
Python中須要用Python string object和Python Unicode object的地方可就不必定能夠直接用QString了!!!
QString向Python string object轉換能夠理解,由於編碼不一樣。
QString向Python Unicode object的轉換?須要轉換嗎?不都是utf16編碼嗎?
QString是tuf16編碼,可是它的實現並不是Python Unicode object那樣直接的utf16碼,而實際是一個QChar串,每一個QChar纔對應unicode符,因此地位至關但並不相同。
許多英文書籍寫到:可使用str()函數直接將QString轉換爲Python string object,可使用unicode()直接將QString轉換爲Python Unicode object。如《PyQt手冊》:
In order to convert a QString to a Python string object use the Python str() builtin. Applying str() to a null QString and an empty QString both result in an empty Python string object.
In order to convert a QString to a Python Unicode object use the Python unicode() builtin. Applying unicode() to a null QString and an empty QString both result in an empty Python Unicode object.
但一樣只適用於英文, 具體見下面分別分析。
1)QString向Python Unicode object的轉換。
>>> from PyQt4 import QtGui, QtCore
>>> unicode(QtCore.QString('def'))
u'def'
>>> print unicode(QtCore.QString('def'))
def
對於中 文,unicode()必需要指定編碼後有效。(這樣也只針對直接的QString有效?對於Qt GUI編程中,從QWidget取得的QString無效?)
>>> from PyQt4 import QtGui, QtCore
>>> unicode(QtCore.QString('中文'))
u'xd6xd0xcexc4'
>>> print unicode(QtCore.QString('中文'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'gbk' codec can't encode character u'xd6' in position 0: il
legal multibyte sequence
指定原始編碼後:
>>> unicode(QtCore.QString('中文'),'gbk','ignore')
u'u4e2du6587'
>>> print unicode(QtCore.QString('中文'),'gbk','ignore')
中文
>>>
GUI編程中:
但這種方法在GUI編程中彷佛無效?
好比建立一個QLineEdit對象myLineEdit,寫入漢字,則:
myText = unicode(self.myLineEdit.text(),'gb2312','ignore')
myText = unicode(QtCore.QString(self.myLineEdit.text()),'gb2312','ignore')
print myText都是亂碼.
嘗試將 unicode()的參數改成QByteArray,但QString沒有toGbk()或toGb2312()函數,只有toUtf8()和 toAsciii()函數,利用下試試:
myText = unicode(self.myLineEdit.text().toUtf8(),'utf8', 'ignore')
myText = unicode(self.myLineEdit.text().toAscii(),'ascii', 'ignore')
由於不是gbk編碼,因此打印都仍是亂碼。
不過python中一 般從文件、終端、網絡數據流或者其它外部輸入中讀取的都是Python string object類型,並且向文件、終端、網絡也只能輸出Python string object類型。因此這個問題能夠跳過,經過下面講的內容,發現能夠在此基礎上轉爲Python string object使用。
2)QString向 Python string object的轉換。
A. 第一種方法:
能夠直接藉助上一步獲得的Python Unicode object和encode()函數得到Python string object。
>>> unicode(QtCore.QString('dfd')).encode('gb2312')
'dfd'
>>> unicode(QtCore.QString('dfd')).encode('ascii')
'dfd'
>>>
>>> unicode(QtCore.QString('中文'),'gbk','ignore').encode('gbk')
'xd6xd0xcexc4'
>>> print unicode(QtCore.QString('中文'),'gbk','ignore').encode('gbk')
中文
>>>
B. 第二種方法:
也可利用str():
>>> str(QtCore.QString('def'))
'def'
>>> print str(QtCore.QString('def'))
def
>>>
可是對於中文,直接調 用str()是無效的!
>>> str(QtCore.QString('中文'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordin
al not in range(128)
對於str()函數默認以ascii編碼轉換,而str()函數又只能接受一個參數,改不了別的編碼,因此對漢字天然不行。
先用unicode()指定gb2312解碼再利用str()呢?:
>>> str(unicode(QtCore.QString('中文'), 'gb2312', 'ignore'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordin
al not in range(128)
仍是----str()函數默認以ascii編碼轉換!
C. 對於中文考慮第一種方法:
>>> unicode(QtCore.QString('中文'),'gbk','ignore').encode('gbk')
'xd6xd0xcexc4'
>>> unicode(QtCore.QString('中文'),'gbk','ignore').encode('gb2312')
'xd6xd0xcexc4'
>>> print unicode(QtCore.QString('中文'),'gbk','ignore').encode('gb2312')
中文
>>> print unicode(QtCore.QString('中文'),'gbk','ignore')
中文
>>>
GUI編程中:
可是對於前面myLineEdit的狀況怎麼處理呢?
myText = unicode(self.myLineEdit.text(),'gb2312','ignore')是亂碼,encode('gb2312')以後 呢?
myText = unicode(self.myLineEdit.text(),'gb2312','ignore').encode('gb2312')
打印依然是亂碼!?
後面嘗試將unicode()的參數改成QByteArray、利用QString的toUtf8()獲得的雖然不是gbk編碼,可是進一步 encode('gb2312')又如何呢:
myText = unicode(self.myLineEdit.text().toUtf8(),'utf8', 'ignore').encode('gb2312')
發現print myText顯示正常!!!:
中文
且python方式打開文件後查找該字符串也正常,證實myText是轉換成功的Python string object!!!
注意:1)藉助 toAscii()函數(除了toUtf8只有這個...)不行?!
myText = unicode(self.myLineEdit.text().toAscii(),'ascii', 'ignore').encode('gb2312')
打印是亂碼。
難道PyQt的Ascii和Python的ascii不同?
2)這種藉助utf8碼的方式對於直接的QString反而不行!?
>>> unicode(QtCore.QString('中文').toUtf8(),'utf8','ignore').encode('gb2312')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'gb2312' codec can't encode character u'xd6' in position 0:
illegal multibyte sequence
>>> unicode(QtCore.QString('中文 ').toAscii(),'ascii','ignore').encode('gb2312')
''
>>> print unicode(QtCore.QString('中文').toAscii(),'ascii','ignore').encode('gb2
312')
>>>
D. 對於中文考慮第二種方法:
利用QString的toAscii()函數後再使用str()函數:
>>> str(QtCore.QString('中文').toAscii())
'xd6xd0xcexc4'
>>> print str(QtCore.QString('中文').toAscii())
中文
>>>
str(QtCore.QString('中文').toAscii())獲得的是ascii編碼?嘗試將其轉爲unicode?
>>> unicode(str(QtCore.QString('中文').toAscii())).encode('gbk')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd6 in position 0: ordinal
not in range(128)
>>> unicode(str(QtCore.QString('中文').toAscii()),'ascii').encode('gbk')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd6 in position 0: ordinal
not in range(128)
>>> unicode(str(QtCore.QString('中文 ').toAscii()),'ascii','ignore').encode('gbk'
)
''
>>>
>>> unicode(str(QtCore.QString('中文').toAscii()))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd6 in position 0: ordinal
not in range(128)
難道PyQt的Ascii和Python的ascii不同?
GUI編程中:
myText = str(self.myLineEdit.text().toAscii())
打印發現仍是亂碼!?
myText = unicode(str(self.myLineEdit.text().toAscii())).encode('gb2312')
打印發現仍是亂碼!?
6. 總結:
1)Python string object是原始編碼是有區分的,經過 decode('原始編碼') 解碼獲得utf16類型即Python Unicode object。Python Unicode object原始編碼固定是utf16,經過 encode('目的編碼') 編碼來獲得Python string object。
2)對於英 文,PyQt函數須要QString參數的地方均可以直接用Python string object或者Python Unicode object。對於中文,利用unicode()函數顯示指定gb2312編碼進行中文編碼轉換,轉換後的Python Unicode object能夠直接做爲QString參數代入。
unicode('中 文', 'gb2312', 'ignore')
3)對於英文,可使 用unicode()直接將QString轉換爲Python Unicode object,並進一步encode()獲得Python string object,也可使用str()函數直接將QString轉換爲Python string object。對於中文,利用unicode()指定原始編碼gbk來解決QString轉換爲Python Unicode object問題,但對於GUI使用仍有缺陷,不過無礙;進一步利用encode('gb2
312')獲得Python string object,或者結合QString的toUtf8()再利用str()函數;但對於GUI編程str()方法仍是不行,只可結合QString的 toUtf8()進行unicode()轉換後再利用encode('gb2
312')。
str(QtCore.QString(' 中文').toAscii())
unicode(QtCore.QString('中文'),'gbk','ignore').encode('gb2312')
myText = unicode(self.myLineEdit.text().toUtf8(),'utf8', 'ignore').encode('gb2312')
7. 中文?爲何不用相似C++中Qt的方法解決上面中文的使用?
C++中Qt通常是利用tr()方法翻譯(便於國際化),或者簡單設置:
QTextCodec::setCodecForTr(QTextCodec::codecForName("GB2312"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB2312"));
1)前者PyQt4中對應是QCoreApplication.translate(),好比pyuic4自動生成的.py文件中能夠看到:
def retranslateUi(self, mainWindow):
mainWindow.setWindowTitle(QtGui.QApplication.translate("mainWindow", "名稱", None, QtGui.QApplication.UnicodeUTF8))
QtGui.QApplication.UnicodeUTF8繼承自QCoreApplication的
enum Encoding { CodecForTr, UnicodeUTF8, DefaultCodec }
但這需保證寫入的漢字是UnicodeUTF8編碼,好比前面myLineEdit讀入的ini文件中漢字就需用utf8表示?CodecForTr是使 用QTextCodec.codecForTr() (Latin-1 if none has been set).但後面可看到PyQt4中無code包?
PyQt4手冊說明以下:
Unfortunately, because of the way Qt implements tr() (and trUtf8()) it is not possible for PyQt to exactly reproduce its behaviour. The PyQt implementation of tr() (and trUtf8()) uses the class name of the instance as the context. The key difference, and the source of potential problems, is that the context is determined dynamically in PyQt, but is hardcoded in Qt. In other words, the context of a translation may change depending on an instance's class hierarchy.
The PyQt behaviour is unsatisfactory and may be changed in the future. It is recommended that QCoreApplication.translate() be used in preference to tr() (and trUtf8()). This is guaranteed to work with current and future versions of PyQt and makes it much easier to share message files between Python and C++ code. Below is the alternative implementation of A that uses QCoreApplication.translate():
class A(QtCore.QObject):
def hello(self):
return QtCore.QCoreApplication.translate("A", "Hello")
2) 但後者方法在PyQt中未能成功: QtCore.QTextCodec.setCodecForTr(QtCore.QTextCodec.codecForName("gb2312")) QtCore.QTextCodec.setCodecForCStrings(QtCore.QTextCodec.codecForName("gb2312")) QtCore.QTextCodec.setCodecForLocale(QtCore.QTextCodec.codecForName("gb2312")) 後證明PyQt4中無code包?ascii也沒有?... if not QtCore.QTextCodec.codecForName("gb2312"): print 'no code'