文件里寫的是unicode,用python怎麼讀取成文本?

文件里直接寫了unicode,比如u5267u60c5這樣

用python讀進來的時候,不管怎麼讀,「」都被轉義成「\」,再轉成unicode就不能識別為文本了,而是變成了u,uu,u5,u2,u6,u7這樣。

我試了2.7和3.3,直接讀成unicode會被轉義,讀成str轉成unicode也會被轉義。

3里有urllib.parse.unquote應該會有幫助,但是讀進來的unicode的被轉義還是沒辦法。。。


差評,文件編輯者估計連什麼是UTF-8都不知道。

正式回答:

# raw_text should be instance of String in Py2, or Bytes in Py3.
raw_text.decode(unicode_escape)

for more, read 7.8. codecs.


其實吧,你需要知道一個 latin-1 的編碼,至於為什麼是latin-1 只有鬼知道了。


因為你如果在文件裡面寫u5267u60c5這樣的文本,肯定會被當成是一個個的字元來處理的,可以自己寫一個parser來處理這種轉義數據

STATE_NORMAL = -1
STATE_SLASH = 0
STATE_BEGIN = 1
STATE_UNICODE = 2

def parser(inpstr):
result =
state = STATE_NORMAL
counter = 0
unicode_hex =

for char in inpstr:
if char == \ and state == STATE_NORMAL:
state = STATE_SLASH
elif char == u and state == STATE_SLASH:
state = STATE_BEGIN
elif state == STATE_BEGIN:
state = STATE_UNICODE
counter = 1
unicode_hex = char
elif state == STATE_UNICODE:
if counter &< 4: if char == \: result += \u + unicode_hex state = STATE_SLASH else: unicode_hex += char counter += 1 if counter == 4: try: result += unichr(int(unicode_hex, 16)) except: result += \u + unicode_hex state = STATE_NORMAL else: result += char if state &>= STATE_SLASH:
result += \
if state &>= STATE_BEGIN:
result += u
if state == STATE_UNICODE:
result += unicode_hex
return result

程序僅為說明方法


回答這個問題,需要我們理清python中的字元種類及字元編碼方式,這樣就能徹底搞清楚類似的問題,我們一個一個的來介紹。

我用我專欄里的一篇文章來仔細講講:

專欄鏈接:給妹子講python,歡迎大家關注,提意見!

先來介紹一下Python中的兩種字元串

Python中有兩種字元串:文本字元串和位元組字元串。其中文本字元串類型被命名為str,內部採用Unicode字符集(兼容ASCII碼),而位元組字元串則直接用來表示原始的位元組序列(用print函數來列印位元組字元串時,若位元組在ascii碼範圍內,則顯示為ascii碼對應的字元,其餘的則直接顯示為16進位數),該類型被命名為bytes。

s = apple
b = bapple
print(b)
print(type(b))
print(s)
print(type(s))

bapple
&
apple
&

再近距離的看看bytes類型位元組字元串,本質上它就是一串單位元組16進位數

b = bapple
print(b[0])
print(b[1:])
print(list(b))

97
bpple
[97, 112, 112, 108, 101]

然後,再來說說編碼與解碼

從本質上來說,編碼和解碼就是str和bytes這兩種字元串類型之間的互相轉換。

str包含一個encode方法,用於使用特定編碼將其轉換為一個bytes,這稱之為編碼。bytes類包含了一個decode方法,也接受一個編碼作為單個必要參數,並返回一個str,這稱之為解碼。這種轉換操作是顯式的操作,且必須根據數據被編碼時採用的編碼類型進行解碼。

首先說說編碼,即將unicode的str文本字元串轉換為bytes的位元組字元串,可以顯示傳入指定編碼(一般採用utf-8編碼),或使用平台的默認編碼

s = π排球の
b1 = s.encode(utf-8)
b2 = s.encode()
print(b1)
print(b2)

bxcfx80xe6x8ex92xe7x90x83xe3x81xae
bxcfx80xe6x8ex92xe7x90x83xe3x81xae

那麼我們看看,在不寫編碼的時候,平台默認的編碼方式到底是什麼

import sys
print(sys.platform)
print(sys.getdefaultencoding())

win32
utf-8

可以看出平台默認選擇的是utf-8編碼方式。

接下來我們來比較一下unicode、latin-1、ASCII編碼方式的兼容性問題:

首先,非ASCII字元無法使用ASCII編碼轉換成位元組字元串

s = π排球の
b = s.encode(ascii)

Traceback (most recent call last):
File "E:/12homework/12homework.py", line 2, in &
b = s.encode(ascii)
UnicodeEncodeError: ascii codec cant encode characters in position 0-3:
ordinal not in range(128)

其次,Latin-1和unicode編碼方式不兼容。

例如,重音字元會在latin-1字符集和unicode字符集中同時存在,但是通過latin-1和unicode編碼方式編出來的位元組流是不一樣的,注意,雖然unicode字符集是包含了latin-1字符集,但是不代表utf-8編碼方式兼容latin-1編碼方式。因為unicode字符集中除了ascii字符集外,都是採用多位元組的編碼方式,而latin-1一律採用單位元組的方式

s = ?è
print(s.encode(utf-8))
print(s.encode(latin-1))

bxc3x84xc3xa8
bxc4xe8

只有ascii字符集中的字元,三種編碼方式得到的結果才完全一致。對unicode進行編碼的時候,針對常規的7位ASCII文本,由於utf-8以及latin-1編碼方式都是兼容ASCII的,所以結果都是一樣的。

s = abc
print(s.encode(utf-8))
print(s.encode(latin-1))
print(s.encode(ascii))

babc
babc
babc

再來談談decode解碼方法

將bytes類型字元串轉換成str類型的unicode文本字元串也是一樣,要麼指定編碼參數,要麼使用平台的默認參數。這個例子中,我們使用的位元組字元串b是通過utf-8編碼方式將π排球の編碼而形成的位元組字元串

b = bxe6x8ex92xe7x90x83
s1 = b.decode(encoding=utf-8)
s2 = b.decode()
s3 = b.decode(encoding=latin-1)

print(s1)
print(s2)
print(s3)

排球
排球
??』???

值得注意的是,最後一行代碼想通過latin-1解碼位元組字元串,由於位元組字元串是通過utf-8編碼形成,因此這樣解碼形成得到的就是亂碼。

Utf-8編碼是用兩個位元組來表示非ASCII的高128字元,而latin-1則是用一個位元組來一一對應

鋪墊了這麼多,我們再回到問題中來:python如何處理在文本文件讀寫過程中的字元編碼?

當一個文件以文本模式打開的時候,被讀取的二進位存儲數據(也就是存儲的位元組字元串)會自動被解碼(依據顯式提供的編碼名稱或平台默認的編碼名稱),並且將其返回為一個str。寫入文件時,會接受一個str,並且將其傳輸到文件之前自動編碼成位元組字元串。

當一個文件以二進位模式打開時,需要在open方法的模式字元串參數里添加一個b,此時讀取的數據不會以任何方式解碼,而是直接返回其原始內容,即一個bytes對象;寫入文件時,接受一個bytes對象,並且將其傳送到文件中且不進行修改。

在讀取文本文件的時候,如果open函數沒有聲明他們如何編碼,python3會因其所運行的系統而選取默認的編碼方式,默認情況下,python3 期望文件使用 utf-8進行編碼。但由於文件並不總是在同一個系統中被保存和打開,因此會帶來亂碼的風險,所以我們需要顯式的指定編碼。

補充的說明一下,可以很簡單的進行一個分類:處理圖像文件、設備數據流等,可以使用bytes和二進位模式文件處理;而如果要處理的內容實質是文本的內容,例如程序輸出、HTML、國際化文本或CSV或XML文件,則可能要使用str和文本模式文件

例如,我們先把A?BèC用UTF-8編碼後存入utf-8data文件,再來讀取他,具體看看這裡是如何實現的。

s = A?BèC

with open(utf-8data,w,encoding=utf-8) as f:
f.write(s)

with open(utf-8data,r,encoding=utf-8) as f:
u_str = f.read()
print(u_str)

A?BèC

這裡提到了文件讀寫的方法後面的章節會詳細介紹,現在知道他是什麼就好了。

以二進位的形式讀取文件。

還有一種方法,我們之前介紹過,文本字元串在存儲在磁碟的時候會編碼形成位元組字元,因此我們也可以先以位元組字元串的形式從文件中讀取位元組字元串,然後再進行解碼。這樣做的原因有二,一種是所接收的可能是非文本數據,如一個圖像文件,另一個潛在原因是無法確定所讀取文本文件的編碼,可能需要依據其他信息再確定

with open(utf-8data, rb) as f:
byte_str = f.read()

print(byte_str)
print(byte_str.decode(encoding=utf-8))

bAxc3x84Bxc3xa8C
A?BèC

這些內容應該有助於我們更好的在文本處理中使用python.


推薦閱讀:

如何用Python和機器學習炒股賺錢?
Python爬蟲聯想詞視頻和代碼
[譯] Python 3.7 新特性
Python數據分析及可視化實例之可視化圖表應用簡介
Django學習筆記一:搭建簡易博客

TAG:Python | Unicode統一碼 |