編碼方式的區(qū)別以及文本在python2中的應(yīng)用

背景:

????????文本以及字符串處理在網(wǎng)絡(luò)應(yīng)用中隨處可見歹苦,面對(duì)不同的用戶接口調(diào)用方,以及不同的我們需要調(diào)用的接口,可能都會(huì)有不一樣的編碼規(guī)范仔蝌。

? ? ? ? 而我在以前的開發(fā)中,對(duì)于字符串的處理經(jīng)常會(huì)是以猜的方式來處理荒吏,encode敛惊、decode等各種方式都試一遍,發(fā)現(xiàn)哪個(gè)能解決問題就用哪個(gè)绰更,從來沒有真正的了解字符串相關(guān)的原理與邏輯瞧挤。

? ? ? ? 所以,最近通過閱讀《Fluent Python》一書以及一些源碼儡湾、博文特恬,好好了解了一下字符相關(guān)的原理以及在開發(fā)中的應(yīng)用,記錄一下學(xué)習(xí)過程中覺得有用的地方以及一些理解徐钠。


ASCII癌刽,Unicode 和 UTF-8之間的關(guān)系

ASCII碼

? ? ? ??ASCII是最早的編碼,美國發(fā)明尝丐,使用一個(gè)字節(jié)8位显拜,最多可以展示255個(gè)字符,但是ASCII編碼中第一位沒有使用摊崭,僅用字節(jié)的后七位表示了127個(gè)字符讼油。

Unicode?

? ? ? ? Unicode是一種所有符號(hào)的編碼,包含了世界上各種語言的符號(hào)呢簸,目前有一百多萬個(gè)符號(hào)在這個(gè)集合中矮台。

? ? ? ? 但是Unicode只是一個(gè)集合,是把所有的字符就放在這個(gè)集合里根时,它規(guī)定了符號(hào)的二進(jìn)制代碼瘦赫,卻沒有規(guī)定這個(gè)二進(jìn)制代碼應(yīng)該如何存儲(chǔ)。

? ? ? ? 因?yàn)閁nicode表示的字符大部分需要兩個(gè)字節(jié)蛤迎,甚至有的會(huì)更多确虱。如果沒有規(guī)定的存儲(chǔ)方式,或者合適的存儲(chǔ)方式替裆,統(tǒng)一用兩個(gè)字節(jié)來表示所有的字符校辩,那么ASCII碼中本來可以用一個(gè)字節(jié)表示的英文字母窘问,就也需要兩個(gè)字節(jié)表示(第一個(gè)字節(jié)全部是0),這樣如果目標(biāo)全是英文宜咒,就相當(dāng)于占用的存儲(chǔ)空間直接翻倍了惠赫。

UTF-8

? ??????UTF-8(UTF-16)是 Unicode 的實(shí)現(xiàn)方式之一。UTF-8是目前使用最廣的一種 Unicode 的實(shí)現(xiàn)方式故黑。

? ??????UTF-8編碼把一個(gè)Unicode字符根據(jù)不同的數(shù)字大小編碼成1-6個(gè)字節(jié)儿咱,英文字母被編碼成1個(gè)字節(jié),漢字通常是3個(gè)字節(jié)场晶,少量很生僻的字符會(huì)被編碼成4-6個(gè)字節(jié)混埠。這樣在全是英文的地方,就不會(huì)用浪費(fèi)空間诗轻,對(duì)于需要多字節(jié)的漢字钳宪,也能正常展示。

? ? ? ? UTF-8的編碼規(guī)則有一下兩條:

1)對(duì)于單字節(jié)的符號(hào)概耻,字節(jié)的第一位設(shè)為0使套,后面7位為這個(gè)符號(hào)的 Unicode 碼罐呼。因此對(duì)于英語字母鞠柄,UTF-8 編碼和 ASCII 碼是相同的。

2)對(duì)于n字節(jié)的符號(hào)(n > 1)嫉柴,第一個(gè)字節(jié)的前n位都設(shè)為1厌杜,第n + 1位設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10计螺。剩下的沒有提及的二進(jìn)制位夯尽,全部為這個(gè)符號(hào)的 Unicode 碼。

????????如上圖所示為Unicode符號(hào)與UTF-8的對(duì)應(yīng)關(guān)系舉例登馒。

? ? ? ? 識(shí)別UTF-8有多少字節(jié)的核心是:如果一個(gè)字節(jié)的第一位是0匙握,則這個(gè)字節(jié)單獨(dú)就是一個(gè)字符;如果第一位是1陈轿,則連續(xù)有多少個(gè)1圈纺,就表示當(dāng)前字符占用多少個(gè)字節(jié)。

? ? ? ? 因?yàn)閁TF-8在只使用一個(gè)字節(jié)的時(shí)候麦射,和ASCII是一樣的蛾娶,所以UTF-8是可以兼容ASCII的。


?綜上所述潜秋,有如下結(jié)論:

????????Unicode和ASCII是同一種概念蛔琅,是是一種編碼方式。而UTF-8峻呛,UTF-16等是一種存儲(chǔ)方式罗售,在存儲(chǔ)和傳輸上節(jié)約空間辜窑、提高性能的一種編碼形式。


字符相關(guān)在Python中的使用

《Fluent Python》:

Unicode 標(biāo)準(zhǔn)把字符的標(biāo)識(shí)和具體的字節(jié)表述進(jìn)行了如下的明確區(qū)分寨躁。

????????字符的標(biāo)識(shí)谬擦,即碼位,是0~1 114 111的數(shù)字(十進(jìn)制)朽缎,在Unicode 標(biāo)準(zhǔn)中以4~6 個(gè)十六進(jìn)制數(shù)字表示惨远,而且加前綴“U+”。例如话肖,字母A的碼位是U+0041北秽,歐元符號(hào)的碼位是U+20AC,高音譜號(hào)的碼位是U+1D11E最筒。在Unicode 6.3中(這是Python 3.4使用的標(biāo)準(zhǔn))贺氓,約10%的有效碼位有對(duì)應(yīng)的字符。

????????字符的具體表述取決于所用的編碼床蜘。編碼是在碼位和字節(jié)序列之間轉(zhuǎn)換時(shí)使用的算法辙培。在UTF-8編碼中,A(U+0041)的碼位編碼成單個(gè)字節(jié)\x41邢锯,而在UTF-16LE編碼中編碼成兩個(gè)字節(jié)\x41\x00扬蕊。再舉個(gè)例子,歐元符號(hào)(U+20AC)在UTF-8編碼中是三個(gè)字節(jié)——\xe2\x82\xac丹擎,而在UTF-16LE中編碼成兩個(gè)字節(jié):\xac\x20尾抑。

????????把碼位轉(zhuǎn)換成字節(jié)序列的過程是編碼,把字節(jié)序列轉(zhuǎn)換成碼位的過程是解碼蒂培。通俗點(diǎn)講再愈,在開發(fā)過程中會(huì)碰到兩種字符:存儲(chǔ)在機(jī)器中的是字節(jié)序列,展現(xiàn)出來是Unicode字符(人類可讀的文本)护戳。將機(jī)器讀取的文本轉(zhuǎn)為人類可讀的文本就是解碼(decode)翎冲,將人類可讀的文本轉(zhuǎn)為給機(jī)器讀取的文本就是編碼(encode)。

在我們項(xiàng)目中的應(yīng)用

? ? ? ? 在開發(fā)過程中媳荒,為了避免對(duì)接不同的接口或者平臺(tái)的時(shí)候出現(xiàn)編碼方式不同造成的報(bào)錯(cuò)抗悍,我們需要在整個(gè)系統(tǒng)中都統(tǒng)一同一套編碼方式。

? ? ? ? 我們使用tornado框架肺樟,框架中g(shù)et_argument方法默認(rèn)會(huì)將拿到的參數(shù)轉(zhuǎn)為unicode:

? ? ? ? 在我們項(xiàng)目的utils.py文件中檐春,一般也都會(huì)有針對(duì)字符串的編碼轉(zhuǎn)換的方法可以調(diào)用:

?????????在編寫腳本的時(shí)候,在文件頂部定義腳本的編碼方式:

? ? ? ? 在具體使用的地方么伯,也要根據(jù)具體需求將文本解碼為我們所使用的UTF-8疟暖。

Python2規(guī)范化字符編碼

? ??????Python2(從2.5開始)則默認(rèn)使用ASCII。因此直接創(chuàng)建的字符串一般默認(rèn)為ASCII,如果調(diào)用接口或者進(jìn)行需要UTF-8的處理俐巴,需要對(duì)字符串進(jìn)行解碼骨望。

? ? ? ? 在進(jìn)行字符串處理的時(shí)候,可能會(huì)遇到無法編碼或者解碼的報(bào)錯(cuò)欣舵,要根據(jù)具體情況處理擎鸠。

????????一般比較常見的是兩種錯(cuò)誤:UnicodeEncodeError(把字符串轉(zhuǎn)換成二進(jìn)制序列時(shí)),UnicodeDecodeError(把二進(jìn)制序列轉(zhuǎn)換成字符串時(shí))缘圈。這種情況是因?yàn)槟繕?biāo)編碼方式?jīng)]有沒有我們需要編碼/解碼的字符串中的某個(gè)字符或者符號(hào)劣光。在進(jìn)行測(cè)試或者自己的一些簡(jiǎn)單開發(fā)的時(shí)候,可以在使用encode的時(shí)候糟把,增加對(duì)errors的指定處理方式來跳過(實(shí)際開發(fā)中绢涡,需要讓異常正常拋出):

city.encode('cp437', errors='ignore') 跳過錯(cuò)誤。

city.encode('cp437', errors='replace') 將無法編碼的字符用?代替遣疯。

city.encode('cp437', errors='xmlcharrefreplace')把無法編碼的字符替換成XML實(shí)體雄可。

? ? ? ? 對(duì)于有些情況,還可能出現(xiàn)音字符的情況缠犀,對(duì)于同樣一個(gè)字符数苫,可能會(huì)有不同的Unicode編碼方式。如下圖:

? ??????此時(shí)辨液,可以使用unicodedata.normalize函數(shù)對(duì)字符串進(jìn)行Unicode規(guī)范化虐急。

????????這個(gè)函數(shù)的第一個(gè)參數(shù)是這4個(gè)字符串中的一個(gè):'NFC'、'NFD'室梅、'NFKC'和'NFKD'戏仓。我們可以主要使用前兩個(gè):NFC(Normalization Form C)使用最少的碼位構(gòu)成等價(jià)的字符串,NFD把組合字符分解成基字符和單獨(dú)的組合字符亡鼠。具體使用如下:

? ??????unicodedata中的combining()函數(shù)可以用來判斷一個(gè)字符是否是音字符,可以用來將文本中的音字符全部過濾掉敷待。

? ? ? ? 在處理字符串的時(shí)候间涵,還有一些方法可以直接對(duì)字符串進(jìn)行簡(jiǎn)單判斷,靈活運(yùn)用起來會(huì)大大提高開發(fā)效率榜揖。包括isdigital(), startswith(),endswith()等勾哩。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市举哟,隨后出現(xiàn)的幾起案子思劳,更是在濱河造成了極大的恐慌,老刑警劉巖妨猩,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件潜叛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)威兜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門销斟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人椒舵,你說我怎么就攤上這事蚂踊。” “怎么了笔宿?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵犁钟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我泼橘,道長(zhǎng)特纤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任侥加,我火速辦了婚禮,結(jié)果婚禮上担败,老公的妹妹穿的比我還像新娘昔穴。我一直安慰自己,他們只是感情好提前,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布吗货。 她就那樣靜靜地躺著,像睡著了一般狈网。 火紅的嫁衣襯著肌膚如雪宙搬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天拓哺,我揣著相機(jī)與錄音勇垛,去河邊找鬼。 笑死士鸥,一個(gè)胖子當(dāng)著我的面吹牛闲孤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播烤礁,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼讼积,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了脚仔?” 一聲冷哼從身側(cè)響起勤众,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鲤脏,沒想到半個(gè)月后们颜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吕朵,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年掌桩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了边锁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡波岛,死狀恐怖茅坛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情则拷,我是刑警寧澤贡蓖,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站煌茬,受9級(jí)特大地震影響斥铺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坛善,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一晾蜘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧眠屎,春花似錦剔交、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至葫督,卻和暖如春竭鞍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背橄镜。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國打工偎快, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蛉鹿。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓滨砍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親妖异。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 字符是用戶可以讀寫的最小單位。計(jì)算機(jī)所能支持的字符組成的集合绒窑,就叫做字符集棕孙。字符集通常以二維表的形式存在。二維表的...
    劉惜有閱讀 8,117評(píng)論 2 14
  • 字符集和編碼簡(jiǎn)介 在編程中常常可以見到各種字符集和編碼蟀俊,包括ASCII,MBCS,Unicode等字符集钦铺。確切的說...
    蘭山小亭閱讀 8,494評(píng)論 0 13
  • UTF-8 編碼提供了一種簡(jiǎn)便而向后兼容的方法, 使得那種完全圍繞 ASCII 設(shè)計(jì)的操作系統(tǒng), 比如 Unix,...
    謝大見閱讀 4,706評(píng)論 0 3
  • 父親年輕的時(shí)候是村子里出了名的膽大心細(xì)不怕事。 那時(shí)因?yàn)榧依锖⒆佣嘀ぃ质抢洗蟮木壒拭矗踔挟厴I(yè)便輟學(xué)在家。十七八歲...
    淡淡青蓮閱讀 386評(píng)論 8 10
  • 本文參與#漫步青春#征文活動(dòng)烫映,作者:夏梁凡沼本,本人承諾,文章內(nèi)容為原創(chuàng)锭沟,且未在其它平臺(tái)發(fā)布抽兆。 走走停停 默數(shù)著腳下的...
    想做詩人的數(shù)學(xué)系渣渣閱讀 409評(píng)論 0 1