Python 2.x 中 Unicode 的使用

由于 Python 在 1989 年被創(chuàng)造出來债朵,Python 2 發(fā)布于 2000 年子眶,這時 Unicode 還沒有被廣泛應用,所以 Python 2 中對于寬字符集的先天支持不夠完善序芦,使用過程中會有些容易誤解的地方臭杰。本文以中文處理為例,說下對于寬字符集的處理谚中。

先說結論:

  • 所有 Python 源文件的文件頭渴杆,加上 # -*- coding: UTF-8 -*-# coding: u8
  • 所有源文件保存為 UTF-8 編碼
  • 代碼中所有帶有中文的字面值字符串,都使用 Unicode 字符串藏杖,如:s = u'測試中文'
  • 從文本文件中讀取的內容将塑,如果需要對其中的字符做編輯處理,需要在打開文件時指定編碼蝌麸,或者當做字節(jié)流加載后点寥,轉為 Unicode 字符串處理。
  • 將字符串內容保存到文件時来吩,先指定要使用的編碼敢辩,將編碼后得到的數(shù)據寫入文件

細說

一蔽莱、理想狀態(tài)

近幾年相對新一些的開發(fā)語言,已經對 Unicode 有了完善支持戚长,個人理解整體的處理思路是這樣的:
  1盗冷、通過對源文件字符編碼格式處理能力的增強,編譯器可以自動處理源文件的編碼格式同廉,或者默認約定為 UTF-8仪糖,來減少這方面帶來的干擾;
  2迫肖、內存中的字符串锅劝,不存在所謂的編碼問題,只是各個字符序號的一個序列蟆湖;
  3故爵、所謂的 UTF-xx 編碼這樣的說法,只是用于存儲和傳輸過程的需要隅津。UTF 即 Unicode Transformation Format诬垂,定義也說明了其用途。

二伦仍、歷史包袱

對于歷史比較悠久的開發(fā)語言或者開發(fā)工具结窘,由于歷史原因,當年還沒有 Unicode呢铆,所以語言缺乏對于 Unicode 原生的支持晦鞋,一般會通過類庫來做擴展進行支持。個人接觸過的開發(fā)工具有:Delphi 7 及之前版本(之后的我沒用過)中的 Object Pascal棺克、Python 2悠垛。(插句題外話,突然覺得 C 當年是多么機靈娜谊,竟然沒有引入字符串類型确买,沒給自己找麻煩,一切處理交給類庫纱皆,隨時升級湾趾,嘖嘖嘖……)
  以 Python 2 為例,當初的字符串是個字節(jié)流派草,其中每個字節(jié)表示一個 ASCII 碼搀缠。而且實際上,即便一些字節(jié)超出 ASCII 范圍近迁,也一樣能放到字符串中艺普。所以,遇到寬字符集中的字符,一樣可以用字符串表示歧譬,但是計算字符串長度岸浑、獲取特定位置字符時,就會出現(xiàn)問題:

# Python REPL 環(huán)境中的測試
>>> s = '測試中文'
>>> print s, type(s), len(s)
測試中文 <type 'str'> 12

這時就需要一種支持 Unicode 的字符串類型作為彌補:

# Python REPL 環(huán)境中的測試
>>> s = u'測試中文'
>>> print s, type(s), len(s)
測試中文 <type 'unicode'> 4
三瑰步、引起混亂的原因

個人認為矢洲,在開發(fā)環(huán)境對 Unicode 支持不夠完善的情況下,以下幾方面都容易引入問題:

  1. 源文件編碼格式(建議統(tǒng)一使用 UTF-8)
  2. 編譯器對于源文件格式的識別和處理(這個作為代碼編寫者無法干預缩焦,只能按照規(guī)則執(zhí)行)
  3. 編譯器對于源碼中寬字符字面值的理解
  4. 外部數(shù)據的格式读虏,如:外部文件、從網絡獲取的數(shù)據

這幾種情況中:
  1舌界、2 可以通過規(guī)范約定掘譬,能掃清很多干擾泰演。
  3 比較容易處理呻拌,按照語言規(guī)則,讓編譯器按照 Unicode 去處理字面值中的寬字符(如中文)的處理睦焕,類似這樣

s = u'測試中文'
# 這樣編寫藐握,字符串 s 就是按照 Unicode 處理其中內容的

4 是真正要注意的情況。這部分內容不受編程時代碼的約束垃喊,完全決定于外部環(huán)境猾普。對于對 Unicode 支持良好的開發(fā)環(huán)境,獲取數(shù)據時本谜,會保存到一個二進制字節(jié)流中初家,當轉換為字符串表示時,需要指定字符編碼乌助,然后才能做轉換溜在,每一步都很清晰,而且拿到的字符串他托,一定是 Unicode掖肋。而在 Python 2 中,沒有這樣的強制要求赏参,所以就需要自己處理:

# -*- coding: UTF-8 -*-
# 打開文件并讀取內容
fp = open('file.txt', 'r')
data = fp.read()
print type(data)
# 根據數(shù)據實際的編碼格式志笼,轉換為 Unicode 字符串,再進行使用
s = data.decode('gbk')
print type(s)
print s
四把篓、規(guī)則約定總結

本文開頭纫溃,作為結論提出了一些約定的規(guī)范做法,這里再做個總結韧掩。

  1. 所有 Python 源文件的文件頭紊浩,加上 # -*- coding: UTF-8 -*-# coding: u8
  2. 所有源文件保存為 UTF-8 編碼
  3. 代碼中所有帶有中文的字面值字符串,都使用 Unicode 字符串,如:
# -*- coding: UTF-8 -*-
myStr = u'測試中文'
print myStr
print type(myStr)
print len(myStr)
  1. 從文本文件中讀取的內容郎楼,如果需要對其中的字符做編輯處理万伤,需要在打開文件時指定編碼,或者當做字節(jié)流加載后呜袁,轉為 Unicode 字符串處理敌买。
# -*- coding: UTF-8 -*-
# 打開文件并讀取內容
fp = open('file.txt', 'r')
data = fp.read()
print type(data)
# 根據數(shù)據實際的編碼格式,轉換為 Unicode 字符串阶界,再進行使用
s = data.decode('gbk')
print type(s)
print s
  1. 將字符串內容保存到文件時虹钮,先指定要使用的編碼,將編碼后得到的數(shù)據寫入文件
# -*- coding: UTF-8 -*-
s = u'我的中文測試'         # 帶有中文的 Unicode 字符串
data = s.encode('UTF-8')  # 使用指定編碼膘融,轉成數(shù)據
# 將數(shù)據寫入文件
fp = open('file.txt', 'w')
fp.write(data)
fp.close()
五芙粱、案例

Requests 是 Python 中一個強大的的網絡庫,在寫一些爬蟲工具時會用到氧映。在網絡請求完成后春畔,會拿到一個 response 對象。一般情況岛都,通過 response.text 返回的 Unicode 字符串就可以滿足要求律姨。
  最近寫的一個爬蟲工具,就在編碼部分出了問題臼疫。網站一部分頁面是 UTF-8 編碼择份,另一部分是 GBK 編碼。開始的時候并不知道烫堤,統(tǒng)一使用 response.text 來做處理荣赶,但是發(fā)現(xiàn)一些冷僻字出現(xiàn)了亂碼。

問題原因
response 同時提供了 content 屬性和 text 屬性鸽斟。其中:

  • response.content 屬性類型為 str拔创,保存著原始內容的字節(jié)流
  • response.text 屬性類型為 unicode,是從 response.content 內容解碼得到的
    網站的 UTF-8 部分頁面湾盗,直接用 response.text 獲取沒有問題伏蚊。但是對于 GBK 編碼的那部分頁面,恰巧冷僻字比較多格粪,Requests 庫在解碼得到 response.text 的時候躏吊,內部使用了不完善的中文字符集,個人猜測可能是 GB2312 之類的帐萎,導致一些字符不能識別比伏,需要用 GBK 解碼解決。

解決方法

# 對于確定返回內容為 GBK 編碼的情況疆导,通過 GBK 解碼赁项,得到原始的 Unicode
response.content.decode('GBK')

參考鏈接:
Python中的str與unicode處理方法
Python編碼格式說明及轉碼函數(shù)encode和decode的使用

(完)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子悠菜,更是在濱河造成了極大的恐慌舰攒,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悔醋,死亡現(xiàn)場離奇詭異摩窃,居然都是意外死亡,警方通過查閱死者的電腦和手機芬骄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門猾愿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人账阻,你說我怎么就攤上這事蒂秘。” “怎么了淘太?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵姻僧,是天一觀的道長。 經常有香客問我琴儿,道長段化,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任造成,我火速辦了婚禮,結果婚禮上雄嚣,老公的妹妹穿的比我還像新娘晒屎。我一直安慰自己,他們只是感情好缓升,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布鼓鲁。 她就那樣靜靜地躺著,像睡著了一般港谊。 火紅的嫁衣襯著肌膚如雪骇吭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天歧寺,我揣著相機與錄音燥狰,去河邊找鬼。 笑死斜筐,一個胖子當著我的面吹牛龙致,可吹牛的內容都是我干的。 我是一名探鬼主播顷链,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼目代,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起榛了,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤在讶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后霜大,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體真朗,經...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年僧诚,在試婚紗的時候發(fā)現(xiàn)自己被綠了遮婶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡湖笨,死狀恐怖旗扑,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情慈省,我是刑警寧澤臀防,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站边败,受9級特大地震影響袱衷,放射性物質發(fā)生泄漏。R本人自食惡果不足惜笑窜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一致燥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧排截,春花似錦嫌蚤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至认罩,卻和暖如春箱蝠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背垦垂。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工宦搬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乔外。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓床三,卻偏偏與公主長得像,于是被迫代替她去往敵國和親杨幼。 傳聞我的和親對象是個殘疾皇子撇簿,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內容