摘要:如果傳一個(gè)中文,下和下編碼分別是和,可以自己用打印看看文件中寫死,本來(lái)理解是跟這個(gè)文件本身編碼有關(guān),但文件編碼同樣是的情況下,下打印了的超集,下仍然是。
對(duì)編碼問(wèn)題一直一知半解,之前也是得過(guò)且過(guò),正好有個(gè)同事要我?guī)兔憘€(gè)腳本,涉及這方面的問(wèn)題,借這個(gè)契機(jī)研究了一下.
先貼幾篇比較好的:
1.阮老師的上古文章(07年…),雖然古老但對(duì)理解幫助很大,從最基礎(chǔ)講起,邏輯清晰易理解. (ps: 阮老師的博客都有此特點(diǎn), 在這里推薦一波, 從js到linux, 精通前后端, 是可以當(dāng)文檔看的博客): http://www.ruanyifeng.com/blo...
2.最好看了上一篇再看這篇(解釋了py2中為什么不能用 setdefaultencoding): https://blog.ernest.me/post/p...
3.關(guān)于UnicodeDecodeError: https://stackoverflow.com/que...
以及Python3的官方文檔:https://docs.python.org/relea...
=============================================================================
建議以上幾篇理解的差不多后再看正文:
簡(jiǎn)單說(shuō)一下:
2.x中的編碼概念是不夠清晰的,str類型的對(duì)象會(huì)被賦予默認(rèn)編碼,且既可以對(duì)其編碼又可以對(duì)其解碼(單這一點(diǎn)就足夠造成很多混亂…),而我們?cè)诖a中常直接使用帶編碼的str進(jìn)行os庫(kù)相關(guān)的操作,就容易導(dǎo)致很多問(wèn)題。對(duì)于python內(nèi)部來(lái)說(shuō),解釋器處理操作系統(tǒng)的文件目錄相關(guān)的東西時(shí),必須使用unicode。新手如果要讀取文件名并進(jìn)行一些處理時(shí),經(jīng)常遇到亂碼,以及windows和linux下效果不同的問(wèn)題。另外一個(gè)主要場(chǎng)景就是stream,流處理,這個(gè)就是寫文件或者前后端通信之類,這個(gè)相對(duì)前面問(wèn)題來(lái)說(shuō)其實(shí)還算好處理的。然后還有字符串拼接。
3.x去掉了 unicode類型 和 unicode()函數(shù),(也就沒(méi)有u"xxx"這種寫法了),區(qū)分出str類型和bytes類型,而且str不再同時(shí)有encode和decode方法,bytes只有decode,str只有encode
3.x中,沒(méi)有了unicode這個(gè)類型,可以理解為str成為了unicode類型,"All text is Unicode"。而帶編碼的字符串則由bytes類型來(lái)處理。但也不能簡(jiǎn)單地理解為3.x的str和bytes分別對(duì)應(yīng)2.x的unicode和str。
所以2.x處理字符串原則其實(shí)也很簡(jiǎn)單,就是把str當(dāng)成bytes,內(nèi)部只用unicode,外部進(jìn)的和出的都編碼成str。
這里可能有個(gè)疑問(wèn)就是,按之前的理解(假設(shè)已經(jīng)讀了第1篇)unicode是編碼規(guī)則,但不是存儲(chǔ)方式,uft8才是它的實(shí)現(xiàn),才能用來(lái)存儲(chǔ),那么如果python內(nèi)部是用unicode方式處理文本,在內(nèi)存中python解釋器如何正確讀取字符呢?這里要理解清楚所謂實(shí)現(xiàn),其實(shí)多的就是一個(gè)字節(jié)數(shù)的信息,unicode和utf8本質(zhì)上都是一串0和1,只是缺一個(gè)字節(jié)數(shù)量的區(qū)分,即,從信息量上來(lái)說(shuō): unicode + 自身長(zhǎng)度 = utf8。這樣,在python解釋器的處理過(guò)程中,python自然有辦法用自己的標(biāo)記來(lái)正確讀寫“自身長(zhǎng)度”這個(gè)信息,因?yàn)檫@里不需要和外界交互,不需要類似utf8這樣的約定規(guī)則,自己內(nèi)部能正確獲取信息即可。utf8是為了省硬盤空間,內(nèi)存中不太需要這樣的東西。(這段屬于個(gè)人想當(dāng)然的理解,僅供參考)
重點(diǎn),重點(diǎn),重點(diǎn),貼一下py2中處理編碼的原則(摘自上面第3篇),也就是我上面那句總結(jié)的完整版,如果你理解了為什么有這個(gè)原則說(shuō)明差不多理解了py2的編碼:
·所有 text string 都應(yīng)該是 unicode 類型,而不是 str,如果你在操作 text,而類型卻是 str,那就是在制造 bug。 ·在需要轉(zhuǎn)換的時(shí)候,顯式轉(zhuǎn)換。從字節(jié)解碼成文本,用 var.decode(encoding),從文本編碼成字節(jié),用 var.encode(encoding)。 ·從外部讀取數(shù)據(jù)時(shí),默認(rèn)它是字節(jié),然后 decode 成需要的文本;同樣的,當(dāng)需要向外部發(fā)送文本時(shí),encode 成字節(jié)再發(fā)送。
除了上面幾篇,百度還有無(wú)數(shù)其他的講解,本篇就不再贅述原理之類的,上腳本講下實(shí)際應(yīng)用,腳本功能是遞歸遍歷目錄下所有文件:
#-*- coding:utf-8 -*- """ Description : 遞歸遍歷目錄下所有文件(排除目錄),并逐行寫入到指定文件中。 可以分別用py2或py3來(lái)執(zhí)行,結(jié)果相同。 可以不帶參數(shù),或者 python xxxx主要干兩件事: 第一步,把文件路徑解碼成unicode,傳給os用來(lái)遍歷 (僅py2) 第二步,把文件名編碼后寫入文件 這樣正好覆蓋了上面提到的兩個(gè)主要場(chǎng)景。 """ """ Python2: str -> (decode) -> unicode -> (encode) -> str Python3: bytes -> (decode) -> str(unicode) -> (encode) -> bytes """ import sys import os try: PATH = sys.argv[1] except IndexError: # 在這里寫一個(gè)你能找到的名字最亂,里面文件名最雜的文件夾 PATH = r"./" # raw string, 表示不進(jìn)行轉(zhuǎn)義, 如果復(fù)制一個(gè)帶反斜杠后面帶數(shù)字或字母的路徑, 不加上這個(gè)r就會(huì)出錯(cuò) try: WRITE_PATH = sys.argv[2] except IndexError: WRITE_PATH = "abc" # 指定要寫入的文件名 PY2 = sys.version.startswith("2") if PY2: # 不理解編碼的人經(jīng)常用這個(gè)當(dāng)做萬(wàn)能藥,這個(gè)確實(shí)也有用,但嚴(yán)重不推薦使用,見第3篇 # import sys # reload(sys) # sys.setdefaultencoding("utf8") # PATH = PATH.decode() # 這樣就默認(rèn)以u(píng)tf8解碼,由于上面的代碼導(dǎo)致傳進(jìn)來(lái)的PATH會(huì)被默認(rèn)編碼為utf8 # 記住原則,在python內(nèi)處理文本字符串,永遠(yuǎn)保證是unicode類型,所以這里要進(jìn)行解碼。關(guān)于"ignore"參數(shù)見第4篇 # 這里PATH不帶中文時(shí),無(wú)論哪種都會(huì)默認(rèn)為ascii編碼,帶其他非ascii文字時(shí),根據(jù)來(lái)源如果是: # 1. sys.argv傳入,那么PATH的編碼跟操作系統(tǒng)有關(guān)。如果傳一個(gè)中文,windows下和linux下編碼分別是ISO-8859-1和utf8,可以自己用chardet打印看看 # 2. 文件中寫死,本來(lái)理解是跟這個(gè)文件本身編碼有關(guān),但文件編碼同樣是utf8的情況下,windows下打印了Windows-1252(ISO-8859-1的超集),linux下仍然是utf8。所以還是跟操作系統(tǒng)有關(guān) # 這里默認(rèn)在linux系統(tǒng)下執(zhí)行,所以直接用utf8解了,如果要兼容,可以用chardet獲取編碼類型后指定進(jìn)行解碼 PATH = PATH.decode("utf8", "ignore") # if PY3,無(wú)論傳入還是寫死PATH都將會(huì)是```str```類型,當(dāng)然也就不需要也不能進(jìn)行解碼啦 def getf(path): l = [] res = os.listdir(path) for each in res: subpath = os.path.join(path, each) if os.path.isdir(subpath): l.extend(getf(subpath)) else: l.append(each) return l res = getf(PATH) if PY2: # Python2, 由于py2中概念的模糊, 可以直接用"w"打開去寫,而不需要"wb" # 不過(guò)不編碼成utf8的話也是會(huì)拋UnicodeDecodeError的,寫文件需要編碼這個(gè)原則py2還是有的??梢詸z查一下 "%s " % each 的類型毫無(wú)疑問(wèn)是unicode with open(WRITE_PATH, "w") as f: for each in res: f.write(("%s " % each).encode("utf8")) else: # Python3, 可以用w打開然后不編碼直接寫string(即unicode),也是可以成功寫的,不過(guò)那樣結(jié)果是非ascii都亂碼。 # 而編了碼就轉(zhuǎn)為了bytes類型,所以Python3想正確實(shí)現(xiàn)就必須用二進(jìn)制方式打開 (wb) # 如果打開方式和寫入類型不對(duì)應(yīng),會(huì)拋TypeError,很明確 with open(WRITE_PATH, "wb") as f: for each in res: f.write(("%s " % each).encode("utf8"))
總結(jié)下代碼,首先可以看到py3是沒(méi)毛病的,對(duì)編碼的操作概念清晰,沒(méi)有任何困擾。
py2這塊確實(shí)有硬傷,雖然很多時(shí)候也無(wú)所謂,但在要嚴(yán)謹(jǐn)或者專門處理編碼的代碼中,一定要記住開頭貼的原則。
關(guān)于setdefaultencoding,除非實(shí)在不重要的場(chǎng)景,又需要臨時(shí)簡(jiǎn)單解決,可以湊合一下,普通場(chǎng)景不建議用.
原因第3篇解釋得很清楚。另附官方文檔的說(shuō)明如下:
set the current default string encoding used by the Unicode implementation. If name does not match any available encoding, LookupError is raised. This function is only intended to be used by the site module implementation and, where needed, by sitecustomize. Once used by the site module, it is removed from the sys module’s namespace.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41384.html
摘要:的字符串有兩種和,的字符串也有兩種和。不同字符的不同表現(xiàn),讓的和顯得撲朔迷離。在中,嚴(yán)格區(qū)分了和,不同類型之間操作就會(huì)拋出的異常。和之間的轉(zhuǎn)換一圖勝千言和的相互轉(zhuǎn)換指的是具體的編碼規(guī)則的名稱,對(duì)于中文來(lái)說(shuō),它可以是這些值等等。 Python2的字符串有兩種:str 和 unicode,Python3的字符串也有兩種:str 和 bytes。Python2 的 str 相當(dāng)于 Pytho...
摘要:字符編碼表,碼位碼元將編碼字符集中的碼位轉(zhuǎn)換成有限比特長(zhǎng)度的整型值的序列。字符編碼方案,碼元序列化也稱為常說(shuō)的序列化。每個(gè)字節(jié)里的二進(jìn)制數(shù)就是字節(jié)序列。另一個(gè)情況則是壓縮字節(jié)序列的值,如或進(jìn)程長(zhǎng)度編碼等無(wú)損壓縮技術(shù)。 《流暢的Python》筆記。本篇主要講述不同編碼之間的轉(zhuǎn)換問(wèn)題,比較繁雜,如果平時(shí)處理文本不多,或者語(yǔ)言比較單一,沒(méi)有多語(yǔ)言文本處理的需求,則可以略過(guò)此篇。 1. 前言 ...
摘要:,,等屬于不同的字符集,轉(zhuǎn)換編碼就是在它們中的任意兩者間進(jìn)行。一般個(gè)人用的電腦上控制臺(tái)基本上都是編碼的,但運(yùn)維的機(jī)器上基本全是,中文的時(shí)候就會(huì)有酸爽的問(wèn)題。 總結(jié)總結(jié),本文僅適用于python2.x 默認(rèn)編碼與開頭聲明 首先是開頭的地方聲明編碼 # coding: utf8 這個(gè)東西的用處是聲明文件編碼為utf8(要寫在前兩行內(nèi)),不然文件里如果有中文,比如 a = 美麗 b = u美...
摘要:根據(jù)有效范圍作用域分為全局變量和局部變量。類型以開頭標(biāo)識(shí)類型以開頭標(biāo)識(shí)類型以進(jìn)制的字節(jié)碼表示,實(shí)際上是一個(gè)字節(jié)串,回應(yīng)了它的另一個(gè)名字。 < 返回索引頁(yè) 基本語(yǔ)法 Hello World 代碼注釋 關(guān)鍵字 數(shù)據(jù)類型 變量、常量 變量 變量賦值 變量命名 變量的作用域 常量 字符串與編碼 字符轉(zhuǎn)義 字符編碼 字符串操作 運(yùn)算符與表達(dá)式 運(yùn)算符 表達(dá)式 ...
摘要:上一步中執(zhí)行時(shí),明確的指出腳本由解釋器來(lái)執(zhí)行。為了表示更多的中文漢字有了,但是,中華文化博大精深,發(fā)現(xiàn)不夠用,因此有了對(duì)的擴(kuò)展即。但是,用編碼對(duì)于英文只占一個(gè)字節(jié),,一個(gè)中文漢字在卻占三個(gè)字節(jié)可能是中國(guó)人有錢啊,我大天朝。 簡(jiǎn)介: Python是一種解釋型語(yǔ)言,需要解釋器來(lái)執(zhí)行??梢酝ㄟ^(guò)在IDLE下執(zhí)行,也可以在文本文件里寫入代碼,然后將該文件命名為xx.py 然后在Windows下可...
閱讀 3221·2021-09-30 09:48
閱讀 3497·2021-09-22 16:00
閱讀 1071·2019-08-30 13:08
閱讀 3110·2019-08-30 10:53
閱讀 2422·2019-08-29 18:33
閱讀 1596·2019-08-29 12:47
閱讀 904·2019-08-29 12:16
閱讀 1935·2019-08-26 12:02