上半年的KPI,是用python作一個測試樁系統,如今系統框架基本也差很少定下來了。裏面有用到新學的工廠設計模式以及以及經常使用的大牛寫框架的業務邏輯和python小技巧。發現以前本身寫的代碼仍是面向過程思想的多,基本沒有面向對象的思想,近半年看的代碼給了很大的觸動,我須要升級個人技能了,因而也花了挺多時間在這個KPI學習上,如今先總結下在作這個系統時我所面臨到的python的字符編碼問題。html
字符編碼問題,若是處理有問題,可能直接就報錯了;若是處理不得當,中文就會顯示亂碼。這是最初接觸字符編碼遇到問題最簡潔的表達。通常都會遇到如下幾個問題(逐漸升級的頭疼問題):python
1. 使用編輯器或者Python IDE直接打印中文,報錯或者亂碼;mysql
2. 前臺傳輸過來包含中文的字符串在後臺打印,報錯或者亂碼;web
3. DB交互,從DB查詢或者insert的中文,操做時報錯或者亂碼;sql
4. 文件操做,從文件中讀取或者寫文件時,報錯或者亂碼;數據庫
除了第四個問題,暫時我沒遇到過,前面3個問題,我遇到好幾回了;遇到字符編碼問題,若是想着就解決當前的問題,隨便在百度上,狂搜各類方法亂試,可能還真能解決這個問題,可是耗時太長了,下次再遇到同樣會頭炸開,我以爲學習解決這個問題須要通過如下幾個過程:設計模式
1. 簡單的瞭解計算機字符編碼的發展史,ASCII編碼是啥? EASCII是啥?GBK是啥?unicode是啥?UTF-8是啥?UTF-16是啥?若是這些最初級的基本概念不瞭解,後面學習會很困難。服務器
2. 理解python的字符串的數據類型,str和unicode,二者之間是如何轉換的?網絡
3. mysql支持哪些字符?mysql的環境變量跟字符集相關的有七,八個,都是神馬意思?最簡單的要怎麼使用?app
第一:字符編碼的前世此生
1989年,荷蘭人Guido van Rossum發明python語言,第一個公開發行版發行於1991年,當時在那個時代,是不關心編碼問題的並且英文字符個數自己也是有限的,26個字母,10個數字,標點符號,鍵盤上加起來能輸入的字符就一百多個,用一個字節來存儲已經夠了,8個比特位能存256個字符。因而美國人制定了一套字符編碼標準ASCII。最開始的ASCII只定義了128個字符,包括96個字符和32個控制符,所以 ASCII 只使用了一個字節的後7位,最高位都爲0。
隨着時代的進步,計算機開始普及到千家萬戶,計算機進入中國面臨的一個問題就是字符編碼,中國的漢字是人類使用頻率最多的文字,常見的漢字就有成千上萬,大大超出了 ASCII 編碼所能表示的字符範圍了,因而中國人本身弄了一套編碼叫 GB2312,GB2312 編碼共收錄了6763個漢字,同時他還兼容 ASCII,GB 2312的出現,基本知足了漢字的計算機處理須要,它所收錄的漢字已經覆蓋中國大陸99.75%的使用頻率,不過 GB2312 仍是不能100%知足中國漢字的需求,對一些罕見的字和繁體字 GB2312 無法處理,後來就在GB2312的基礎上建立了一種叫 GBK 的編碼,GBK 不只收錄了27484個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數民族文字。一樣 GBK 也是兼容 ASCII 編碼的,對於英文字符用1個字節來表示,漢字用兩個字節來標識。
世界語言種類有多少,計算機的字符編碼相應就會增長多少。因而統一聯盟國際組織提出了Unicode編碼,Unicode的學名是」Universal Multiple-Octet Coded Character Set」,簡稱爲UCS。Unicode有兩種格式:UCS-2和UCS-4。UCS-2就是用兩個字節編碼,一共16個比特位,這樣理論上最多能夠表示65536個字符,不過要表示全世界全部的字符顯示65536個數字還遠遠不過,由於光漢字就有近10萬個,所以Unicode4.0規範定義了一組附加的字符編碼,UCS-4就是用4個字節(實際上只用了31位,最高位必須爲0)。世界上任何一個字符均可以用一個Unicode編碼來表示,一旦字符的Unicode編碼肯定下來後,就不會再改變了。可是Unicode有必定的侷限性,一個Unicode字符在網絡上傳輸或者最終存儲起來的時候,並不見得每一個字符都須要兩個字節,好比一字符「A「,用一個字節就能夠表示的字符,卻使用兩個字節,太浪費空間了。UTF-8(8-bit Unicode Transformation Format)就出現了,UTF-8是一種針對Unicode的可變長度字符編碼,又稱萬國碼。UTF-8用1到6個字節編碼Unicode字符。
第二:python 字符串類型
python2.X 系統的默認編碼是ASCII,3.X系統就是unicode,因此在2.X系列遇到的編碼問題會更多。
1
2
3
4
5
|
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
|
如今會遇到第一類問題,在python源代碼文件中若是不顯示地指定編碼的話,將出現語法錯誤:
這個提示很明顯,非ASCII碼在源代碼中出現了。單純的出現這類問題,能夠採用如下方法解決:
方法一:在 文件前指定編碼格式:
#!/usr/bin/env python #coding:UTF-8
方法二:設置整個系統的字符編碼才能解決問題:(結合方法一一塊兒使用)
default_encoding = 'utf-8'
if sys.getdefaultencoding() != default_encoding: reload(sys) sys.setdefaultencoding(default_encoding)
方法一和方法二都嘗試了還有問題,可能就是你的編輯器的顯示問題了,我使用的是pycharm,在file-setting裏能夠這樣的設置:
調試IDE編碼和project編碼後,終於能打印中文了:
以前,剛學習python的時候,總結的一段:
1. 不設置源文件編碼格式,輸入中文,後直接打印,會提示存在‘non-ascii’,編譯不經過
2. 設置源文件編碼格式爲gbk,輸入中文後,打印亂碼
3. 設置源文件編碼格式爲gbk,輸入中文s1 = u'測試'後,打印正常
4. 設置源文件編碼格式爲gbk,輸入中文後,先將字符串解碼decode或者unicode方法,後打印正常
5. 設置源文件編碼格式爲utf-8,輸入中文後直接輸出正常
6. 設置工具和工程的默認編碼爲gbk,輸入中文後,打印正常。
從python2.0開始,就有一種新的數據類型 Unicode Strings,可是在python3的到來,這個概念已經被弱化了。python2.*的默認編碼格式是ASCII碼,而python3.*的默認編碼格式已經換成了Unicode。在python2中和字符串相關的數據類型,分別是str、unicode兩種,他們都是basestring的子類,可見str與unicode是兩種不一樣類型的字符串對象。區分一個
變量是字符仍是unicode,可使用type方法:
>>> a='好'
>>> type(a) <type 'str'>
>>> a '\xe5\xa5\xbd'
>>> b=u'好'
>>> type(b) <type 'unicode'>
>>> b u'\u597d'
Python中str和unicode之間是如何轉換的呢?這兩種類型的字符串類型之間的轉換就是靠這兩個方法decode
和encode
。
這2個函數的具體使用,就不舉例了。網上這類文章挺多的。這時就有可能遇到第二個問題,前臺傳入的中文在後臺亂碼,沒法處理。通常出現這類問題,都是先後臺編碼格式不一致致使的;
方法一:統一先後臺編碼格式;
方法二:若是沒法統一,那取數據的時候就須要進行轉碼處理,以前我遇到一個問題,前臺傳入的是GBK格式的中文,我是作後臺處理的,後臺全系統都是用utf8編碼的,接收到GBK的http請求後,顯示的中文是亂碼的,致使解析那段GBK的xml都報異常。後面作了調整,再接收到前臺的GBK字符串後,首先decode(gbk)再encode(utf8)就成功了。
第三:操做DB,須要瞭解的mysql字符集。
使用python對DB的操做,隨時都有可能出現亂碼。網上搜如下2個方法偶爾也能解決問題:
方法一:conn = MySQLdb.connect(self.host,self.username,self.password,self.database,charset='gbk')
方法二:
一、 客戶端和服務器創建鏈接後,客戶端以什麼字符編碼發送數據?
答:服務器以character_set_client系統變量被設置, conn = MySQLdb.connect(self.host,self.username,self.password,self.database,charset='gbk') 只是設置了客戶端發生數據的字符編碼格式
二、服務器在收到語句後將其翻譯成什麼字符集?
答:服務器使用character_set_connection和collation_connection系統變量。它將收到的字符集從character_set_client轉到character_set_connection,而後再進行處理。