Python2 顯示 unicode


用戶想要看的是 u'中文' 而不是 u'\u4e2d\u6587',但是在 Python2 中有時並不能實現。

轉譯

轉義字符是這樣一個字符,標志着在一個字符序列中出現在它之后的后續幾個字符采取一種替代解釋[1]。

>>> ["\u4e2d\u6587"] == ["中文"]
True
>>> '["\u4e2d\u6587"]' == '["中文"]'
True

# 取消轉義后則不相等
>>> r'["\u4e2d\u6587"]' == r'["中文"]'
False
>>> r'["\u4e2d\u6587"]'
'["\\u4e2d\\u6587"]'
>>> r'["中文"]'
'["中文"]'

由於各種語言的轉義機制是不一樣的,所以傳遞 '["\u4e2d\u6587"]' 到瀏覽器上,瀏覽器顯示的是未轉義的 '["\u4e2d\u6587"]'

str()

Python2 str is bytes.

  • unicode encode to bytes
  • bytes decode to unicode
>>> b = u'中文'.encode('utf-8')
>>> type(u'中文')
<type 'unicode'>
>>> type(b)
<type 'str'>
>>> b
'\xe4\xb8\xad\xe6\x96\x87'
>>> b.decode('utf-8') == u'中文'
True

對於 unicode,str() 相當於以默認 encoding 編碼:

# -*- coding: utf-8 -*-

import sys
try:
    str(u'中文')
except UnicodeEncodeError:
    print(u'不能使用 {encoding} 編碼非 {encoding} 字符'.format(encoding=sys.getdefaultencoding())) # 不能使用 ascii 編碼非 ascii 字符

reload(sys)
sys.setdefaultencoding('UTF8')
print(sys.getdefaultencoding()) # UTF8

print(str(u'中文')) # 中文
print(str(u'中文') == u'中文'.encode(sys.getdefaultencoding())) # True

容器內的 unicode 顯示

容器 指一個類、數據結構或者一個抽象數據類型,對應的實例是其他對象的集合。在 Python 中,listdict 都是容器。

在 Python 中,str(container) 對每個 item 調用 repr() 而不是 str() 以獲取對應的字符串[2]。而在 Python2 中,repr() 返回一個對象的可打印字符串形式,但是會使用 \x\u 或者 \U 轉譯字符串中的非 ASCII 字符[3]。

所以我們會看到這樣的現象

>>> print({u'\u4e2d\u6587': 1})
{u'\u4e2d\u6587': 1}

而在 Python3 中,repr() 只會轉譯不可打印的象形符號(glyphs),所以在 Python3 中

>>> print({u'\u4e2d\u6587': 1})
{'中文': 1}

Python 將 print() 中的參數轉換為 bytes str,然后輸出到 sys.stdout 上。

目前不清楚如何轉換的,只知道不是用 str() 轉換:

# -*- coding: utf-8 -*-

print(u'中文') # 中文
print(str(u'中文')) # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

處理

顯示時將 unicode 以 utf-8 編碼為 bytes。

由於 Python2 的默認編碼是 ASCII 並且 str() 不支持 encoding 參數,所以不能使用 str()

更改默認編碼也不可取[4]。

目前我找到的辦法是使用 json.dumps(obj, ensure_ascii=False)

If ensure_ascii is true (the default), all non-ASCII characters in the output are escaped with \uXXXX sequences, and the result is a str instance consisting of ASCII characters only. If ensure_ascii is false, some chunks written to fp may be unicode instances.

>>> print(json.dumps([u'\u4e2d\u6587', ], ensure_ascii=False))
["中文"]
>>> print(json.dumps([u'\u4e2d\u6587', ], ensure_ascii=True))
["\u4e2d\u6587"]

參考

  1. https://zh.wikipedia.org/zh-hans/轉義字符
  2. https://www.python.org/dev/peps/pep-3140/
  3. https://docs.python.org/3/library/functions.html#ascii
  4. https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM