一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

黃聰:解決python中文處理亂碼,先要弄懂“字符”和“字節(jié)”的差別

 dbn9981 2016-09-24
我來講一下字符問題我的理解吧,雖然我對Python的編碼處理的具體細節(jié)還不太清楚,不過臨時稍微看了一下,和Perl的原理也差不多
  
最重要的是必須區(qū)分“字符”和“字節(jié)”的不同,“字符”是抽象的,而“字節(jié)”是具體的
  
比如一個“中”字,在不同編碼中用如下字節(jié)表示:
  
    GBK      Big5        UTF-8     UTF-16LE
\xD6\xD0  \xA4\xA4  \xE4\xB8\xAD  \x2D\x4E
  
所謂“抽象”的“字符”的“中”,并不是指“\xD6\xD0”或“\xA4\xA4”或任何字節(jié),應該把它理解成:GBK編碼中“\xD6\xD0”字 節(jié)所指代的那個字符(語言學中的能指→所指),或者UTF-8編碼中“\xE4\xB8\xAD”所指代的那個字符,但并不是這些具體字節(jié)本身
  
問題是,抽象的字符要作為數據進行存儲和傳遞,就必須有具體的形式,也就是說你在程序內部實現中,要存儲“中”這個字符,你必須采用某些特定的字節(jié)。你可 以用“\xD6\xD0”,也可以用“\xE4\xB8\xAD”,也可以用“\x2D\x4E”,Python在Windows下采用的是UTF- 16LE(?),也就意味著它的“字符”的載體編碼是UTF-16LE
  
sys.setdefaultencoding(name)
Set the current default string encoding used by the Unicode implementation.
  
文檔上是這么寫的,如果我的理解沒錯的話,這個函數的作用就是改變“字符”的載體編碼,sys.setdefaultencoding('gbk')以后,“中”這個字符在程序內部就不是用“\x2D\x4E”來承載,而是用“\xD6\xD0”來承載了
  
Python2.x里的str和unicode有什么區(qū)別呢?從字面意義上看容易混淆,實際上,你可以把它理解成str是“字節(jié)串”,unicode是“字符串”(string總是翻譯成“字符串”,在這里就很容易把人繞暈),看下面的例子:
  
# -*- coding: gb2312 -*-
  
s = "張三李四"
print len(s) #=> 8
u = s.decode('gbk')
print len(u) #=> 4
  
我的腳本編碼用的是GBK,而不是UTF-8,你會看到len(s)是8,這是這四個漢字所用的實際8個“字節(jié)”,而len(u)是4,這就表示這里有4個“字符”
  
encode和decode是什么意思呢?所謂編碼,就是把意義轉換成符號;而解碼,就是把符號還原成意義。在這里,encode應該理解成把抽象的字符轉換成具體的字節(jié),而decode是把具體的字節(jié)還原成抽象的字符
  
現在的問題是:str類和unicode類都同時具有encode和decode方法,這是一個讓我很不以為然的設定。如果按照字節(jié)與字符的區(qū) 分,encode方法是應該只歸unicode類所有,decode方法是只歸str類所有的,因為“意義”只能轉換成“符號”,“意義”再還原成“意 義”這本身就沒有意義。
  
假如我們這樣:
  
# -*- coding: gb2312 -*-
  
s = "張三李四"
u = s.decode('gbk') # 沒問題,字節(jié)解碼為字符,符號還原為意義
s2 = s.encode('gbk')
  # 出錯了!字節(jié)沒法再編碼成字節(jié),除非s全部是ASCII字符,但是這樣s2和s是完全等同的,這個操作有什么意義?
u2 = u.decode('gbk')
  # 又出錯了!也只能u只包含ASCII字符,u2和u也是完全等同,這個操作也沒有意義
  
在這里提一下Perl的處理方式,我不知道Python處理編碼的原理是否是直接得自Python,還是說這是各門語言共同的做法(但是Ruby又不是這樣做的),總之Python2.x是有缺陷的
  
Perl里只有一種string,它實際也區(qū)分字符串和字節(jié)串(以UTF-8作為底層的承載編碼),但不像Python2.x分str和unicode, 而是string內部有一個utf8的flag,這個flag是on的時候,這個string就是一個“字符”串,這個flag是off的時候就是一個 “字節(jié)”串,它的編碼、解碼函數如下:
  
$octets = encode(ENCODING, $string [, CHECK])
  
$string = decode(ENCODING, $octets [, CHECK])
  
$octets就是字節(jié)串,$string就是字符串,也就是說,encode只對$string起作用,而decode只對$octets起作用,不像 Python是str和unicode兩類兩個方法都有,但是其實各有一個是沒用的。Larry Wall是語言學家,他設計的這一套字符、字節(jié)關系是完全符合語言學中的“能指-所指”理論的,而GvR恐怕就對語言學不在行了,Python的處理就不 怎么精妙了。
  
再來說一下file.write為什么有編碼問題:
  
# -*- coding: gb2312 -*-
  
  
s = "張三李四"
u = s.decode('gbk')
  
f = open('text.txt','w')
f.write(u) # 出錯!
f.write(u.encode('gbk')) # 這樣才行
  
出錯的原因很簡單,你想輸出的是“字符”,而不是“字節(jié)”。上面說過,“字符”是抽象的,你是沒有辦法把一個抽象的東西寫到文件里去的。雖然抽象的字符下 面肯定是有具體的承載字節(jié)的,但是Python似乎并不愿意把unicode底層的字節(jié)跟IO攪在一起,這就導致f.write(a_unicode)的 失敗,當然a_unicode假如只包含ASCII字符,這個可以成功,然而這是一種捷徑,是一條讓人越來越糊涂的捷徑
  
然后再是u標記的意義是什么?很簡單,就是自動完成字節(jié)→字符的轉換
  
# -*- coding: gb2312 -*-
  
s_or_u1 = "張三李四"
print type(s_or_u1) #=> <type 'str'>
  
s_or_u2 = u"張三李四"
print type(s_or_u2) #=> <type 'unicode'>
  
u"張三李四"就相當于"張三李四".decode(a_enc),這里的a_enc就是#coding行設定的gb2312
  
不得不說,(不知是不是從Perl得來的)這套字符處理方式很晦澀,字符、字節(jié)區(qū)分的概念實在不太容易理解,而Python本身的細節(jié)處理也沒有做 好,Perl做得很干凈了,都不容易理解,Python沒做干凈更不行了。另外再附贈簡單介紹Ruby的字符處理方式,跟Perl完全不同:
  
Ruby中沒有字符、字節(jié)的區(qū)分,一切字符串都是“帶有一個編碼屬性的字節(jié)串”。因為沒有抽象的字符,所以就沒有字節(jié)→字符的轉換,也就根本沒有、也不需 要decode方法,Ruby的String類只有encode方法。因為沒有抽象的“字符”概念,Ruby的編碼問題應該比Perl、Python容易 理解。沒有“字符”的還有一個好處是:處理多字節(jié)文本無需經過中間轉換。你要在Perl里處理中文字符,來源文件是GBK編碼的,實際都得先轉換成 UTF-8,Perl才能處理:Python要先轉化成UTF-16才能處理。對于海量文本來說,這一轉換過程肯定是要耗費一定的資源的。而Ruby不需 要這種轉換,直接就能處理GBK或其他編碼了??赡苓@樣做也是考慮了日文的實際,日文的shift-jis(?)是本土編碼,根本都不跟ASCII兼容, 不像GBK是跟ASCII兼容的,這樣做就不必轉換就能處理土著編碼的文檔了。如果說Perl的字符-字節(jié)區(qū)分是語言學家的學院派做法的話,Ruby就是 契合了多字節(jié)字符處理需要的實用派做法。

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    99久久精品午夜一区二| 在线中文字幕亚洲欧美一区| 91久久国产福利自产拍| 国产肥妇一区二区熟女精品| 日韩日韩日韩日韩在线| 千仞雪下面好爽好紧好湿全文| 欧美一区二区三区视频区| 国产成人精品综合久久久看| 国产精品午夜福利免费阅读 | 日本人妻精品中文字幕不卡乱码 | 国产又大又猛又粗又长又爽| 91人妻久久精品一区二区三区| 国产激情一区二区三区不卡| 好吊妞视频只有这里有精品| 我想看亚洲一级黄色录像| 国产精品成人一区二区在线| 日本一区二区三区久久娇喘| 殴美女美女大码性淫生活在线播放| 午夜福利网午夜福利网| 国产一级内片内射免费看| 偷拍偷窥女厕一区二区视频| 日韩国产亚洲欧美另类| 日韩一区二区三区在线欧洲| 好吊色免费在线观看视频| 欧美黑人黄色一区二区| 欧美国产日产在线观看| 免费高清欧美一区二区视频| 日本三区不卡高清更新二区| 老司机精品福利视频在线播放| 在线免费观看黄色美女| 日韩精品综合福利在线观看| 国产一区欧美一区二区| 大香蕉网国产在线观看av| 色一欲一性一乱—区二区三区| 日韩一区欧美二区国产| 亚洲一区二区福利在线| 国产又粗又猛又大爽又黄同志| 欧美成人国产精品高清| 五月综合激情婷婷丁香| 精品欧美日韩一二三区| 久久经典一区二区三区|