天天看點

《Python Cookbook(第2版)中文版》——1.21 在Unicode和普通字元串之間轉換

本節書摘來自異步社群《python cookbook(第2版)中文版》一書中的第1章,第1.21節,作者[美]alex martelli , anna martelli ravenscrof , david ascher ,高鐵軍 譯,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

任務

需要處理一些可能不符合ascii字元集的文本資料。

解決方案

普通字元串可以用多種方式編碼成unicode字元串,具體要看你究竟選擇了哪種編碼:

讨論

如果想處理含有非ascii字元的文本資料,首先要懂一些unicode—什麼是unicode、unicode怎麼工作、python如何處理unicode。前一節提供了少量卻很重要的指導,本節将在這個話題下繼續深入讨論。

不用在完全了解unicode的一切之後,才去處理現實世界中的有關unicode的問題,但是一些基本知識卻是不可或缺的。首先,需要了解位元組和字元之間的差別。在過去的以ascii字元為主體的語言以及環境中,位元組和字元被認為是同一種東西。一個位元組可以有256個不同的值,是以環境被限制為隻能處理不超過256個不同的字元。而另一方面,unicode則支援成千上萬的字元,那也意味着每個unicode字元占用超過1個位元組的寬度。是以,首先需要搞清楚字元和位元組之間的差別。

标準的python字元串實際上是位元組串,這種字元串中的每個字元,長度為1,實際上就是一個位元組。我們還可以用python的标準字元串類型的其他一些術語來稱其為8位字元串或者普通字元串。在本節中,我們稱這種類型的字元串為位元組串,以此來提醒你它們的單位元組的特點。

python的unicode字元是一個抽象的對象,它足夠大,能夠容納任何字元,可以同python的長整數進行類比。完全無須擔心它的内部表示;隻有當你試圖将它們傳遞給一些基于位元組處理的函數時—比如檔案的write方法和網絡socket的send方法,unicode字元的表示才會成為一個問題。基于這個原因,必須選擇以何種方式将這些字元表示成位元組。将unicode字元串轉化成位元組串被稱為對該字元串編碼。同樣的,如果從一個檔案、socket或者其他基于位元組的對象中載入一個unicode字元串,必須對其解碼,将其從位元組轉成字元。

從unicode對象轉化成位元組串有很多方法,這些方法都被稱為某種編碼。由于一系列曆史的、政治的、以及技術上的原因,沒有哪種編碼是“正确”的。每種編碼都有個大小寫不敏感的名字,這個名字可以被傳遞給encode和decode函數作為參數。下面給出一些應該知道的編碼。

utf-8編碼可以應用于任何unicode字元。它也向後相容ascii,是以一個純粹的ascii檔案也可以被認為是一個utf-8檔案,而隻使用ascii字元的utf-8檔案,也完全等同于使用這些字元的ascii檔案。這個屬性使得utf-8具有極好的向後相容能力,特别是對一些老的unix工具來說。utf-8是迄今為止unix上最具主導性的編碼,同時也是xml文檔的預設編碼。utf-8的主要弱點是,對于一些東方的語言文本,它的效率比較低。

utf-16是微軟作業系統和java環境喜愛的編碼。它對于西方語言效率略低,但對于東方語言卻更有效率。utf-16有一個變種,被稱為ucs-2。

iso-8859系列的編碼是ascii的超集,每種編碼都能處理256個不同的字元。這些編碼不能支援所有的unicode字元;它們隻支援一些特定的語系或語言。iso-8859-1,也以“latin-1”的名字為人所知,覆寫了大多西歐和非洲的語言,但不包括阿拉伯語。iso-8859-2,也被稱為“latin-2”,覆寫了很多東歐的語言,比如匈牙利和波蘭。iso-8859-15,現在在歐洲非常流行,基本上它和iso-8859-1一樣,但增加了對歐洲貨币符号的支援。

如果想對所有的unicode字元編碼,你可能需要用utf-8。當需要處理别的程式或者輸入裝置用其他編碼建立的資料時,你才可能需要用到其他編碼,或者相反,在需要輸出資料給你的下遊程式或者輸出裝置,而它們采用的是另一種特定的編碼時。第1.22節展示了一個例子,這個例子中,可以看到怎樣通過程式的标準輸出來驅動其他下遊程式或裝置。