Python字符編碼詳解

本文詳細講解字符編碼的相關知識,包括字符編碼的發展歷程,字符編碼的使用,在python中字符編碼的應用html

首先要明確:計算機中的全部數據,不管是文字、圖片、視頻、仍是音頻文件,本質上最終都是按照相似 01010101 的二進制存儲的python

拓展1:什麼是編碼,解碼?

1.信息的兩種狀態:

1)明文狀態:相似顯示器上能看到的消息,內容等,存儲在內存中,是處於運行狀態的信息,通常是用Unicode萬國碼存儲的數據流(或者叫信息流,字節流等)
2)文件狀態:相似硬盤文本文件中存儲的數據或者信息,相對來講是處於靜止的狀態,存儲方式爲二進制0101
3)人能夠看懂顯示器上的明文,計算機能夠看懂文本中的二進制數據
4)將明文(內存中的信息流)從內存中保存到硬盤文件中的過程須要用到「編碼」操做,將文本內容從硬盤讀到內存中的過程須要用到「解碼」操做
5)「編碼」就是咱們保存文件的過程,解碼」就是咱們打開文件的過程,這兩個過程是互逆的linux

拓展2:字符與字節

1.字符

顯示器能夠看到的漢字或英文就是字符程序員

不一樣編碼下一個字符佔用的內存或磁盤空間不一樣編程

2.字節(B,Byte)

是計算機存儲的最小單位,一字節等於八位
是計算機編程語言中的數據類型和語言字符。json

3.位(b,bit,比特)

數據傳輸的最小單位vim

4.B與bit

數據存儲是以「字節」(Byte)爲單位,數據傳輸大可能是以「位」(bit)爲單位,
一個位就表明一個0或1(即二進制),每8個位組成一個字節windows

5.B與iB

1)數據的存儲與傳輸
數據存儲是以10進製表示,數據傳輸是以2進製表示的,因此1KB不等於1000B。網絡

1KiB(Kilobyte)=1000byte
1MiB(Megabyte)=1000000byte
1KB(Kibibyte)=1024byte
1MB(Mebibyte)=1048576byte

2)硬盤標稱容量與實際容量編程語言

硬盤生產商是以十進制,GiB(即10的3次方=1000,如1MiB=1000KB)計算的,
而電腦是以2進制,GB(即2的10次方, 如1MB=1024KB)計算的
可是國內用戶通常理解爲1MiB=1M=1024 KB, 因此爲了便於中文化的理解,翻譯MiB爲MB也是能夠的。

3)單位轉換

1B=1Byte=8bit
1KB=1024B
1MB=1024KB
1GB=1024MB
1TB=1024GB
1PB=1024TB
1EB=1024PB
1ZB=1024EB
1YB=1024ZB
1BB=1024YB

======== 分割線 =======

1.常見的編碼格式

1.1.ASCII碼:最先的字符編碼

1)全稱:美國標準信息交換代碼,American Standard Code for Information Interchange
2)設計初衷:爲了與計算進行交互設計出ASCII碼,是基於拉丁字母的一套電腦編碼系統,主要用於顯示現代英語和其餘西歐語言
3)設計原理:計算機上的數據都是以二進制的形式存儲的,1個字節(8比特)能夠表示256種狀態,英文只有26個字符,再加上一些特殊字符,使用128個就夠了,計算機就可使用127個不一樣字節來存儲英語文字,就是ASCII編碼
最開始的時候8位中的最高位是沒有用到的,後來爲了表示拉丁文,將最高位用上造成擴展ASCII編碼,一個字節就用滿了。
4)編碼規定:每一個字符(英文字符)最多隻能用一個字節(8 位bit)來表示,全部字符都各佔1個字節
即:2**8 = 256-1,因此,ASCII碼最多隻能表示 255 個符號。

1.2.GB2312 (1981)(關於中文的處理)

1)設計初衷:計算機進入中國後,沒法顯示中文,現有的ASCII已經被佔滿了沒法編碼中文,因而制定GB2312,
2)設計原理:將ASCII碼擴展的第八位對應的拉丁文所有刪掉,規定一個小於127的字符與原來的意義相同,當兩個大於127的字符連接在一塊兒的時候,就表示一個漢字,前面一個字節爲高字節(0xA1-0xF7),後面一個字節爲低字節(0xA1-0xFE),這樣能夠表示7445箇中文字符
3)編碼特色:收錄7445箇中文字符,6763個漢字和682個其餘符號,GB2312是對ASCII的中文擴展,是支持中文的第一張表

1.3.GBK1.0 (1995) (GBK)

1)設計初衷:因爲漢字的數量太大,GB2312不能知足需求
2)設計原理:規定只要第一個字節大於127就固定表示一個漢字,無論後面的是否是擴展字符集裏面的內容,擴展後的編碼爲GBK1.0版本
3)編碼特色:GBK包括了GB2312的全部內容,收錄21886箇中文字符(包括繁體)和符號
4)編碼規定:1箇中文字符佔2個字節

1.4.GB18030 (2000)

1)設計初衷:是爲了取代GBK1.0的正式國家標準,
2)設計原理:略
3)編碼特色:該標準收錄27484個漢字,和其餘藏文,蒙文,維吾爾文,繁體,日文,朝鮮語等主要的少數名族文字,GB18030相對GBK增長的字符普通人很難用到
4)編碼規定:1箇中文字符佔2個字節

1.5.Unicode萬國碼:統一的字符編碼

1)其餘名稱:也叫統一碼,單一碼
2)設計初衷:因爲ASCII碼沒法表示世界上全部國家和地區的文字和符號,每一個國家都搞本身的編碼,彼此之間互不支持,帶來不少麻煩,因此設計出Unicode
3)編碼特色:能夠提供65535種字符,支持了全球各個國家的語言編碼,且包含了與全部國家編碼的映射關係
4)編碼規定:全部的文字和符號最少由2個字節(16位)來表示,可能更多,通常是2-4個字節
即:2**16 = 65535 = 存一個字符,統一佔用2個字節

1.6.UTF-8字符集

1)設計初衷:因爲Unicode使用2-4個字節,對於英文世界的國家來講,一個字節徹底夠用,使用Unicode會形成空間浪費
2)設計原理:對Unicode進行優化產生一種可變長的字符編碼集,根據不一樣的符號變化字節長度,當字符在ASCII編碼範圍時,用一個字節表示,兼用ASCII,在存儲和傳輸時更加節省空間
3)編碼規定:英文字符用ASCII碼來存,一個英文字符佔1個字節,一個歐洲語言字符佔2個字節,1箇中文字符佔3個字節
4)其餘不一樣的Unicode擴展集:
utf-16:一個字符佔2個字節或2個以上,能夠存2的16次方,共65535個字符
utf-32:一個字符佔4個字節
5)Unicode和utf-8的關係:Unicode是內存編碼方案(規範標準),而utf-8是字符集,是保存和傳輸Unicode的是實現方式
通常不直接用Unicode,而是用UTF-8等字符編碼

注意:
1)以上幾種編碼,後面的編碼兼容前面的標準,在這些編碼中,英文和中文能夠統一處理。
unicode向下兼容gb2312 , gbk
2)區分中文編碼的方法是高字節的最高位不爲0。
3)按照程序員的習慣,GB23十二、GBK1.0到GB18030都屬於雙字節字符集 (DBCS)。
4)中國規定:進入中國的軟件必須支持GBK,PC平臺要求必須能支持GB18030,嵌入式產品,如手機,MP3等不作要求,只須要支持GB2312便可
5)不管以何種編碼在內存裏顯示字符,存在硬盤上後都是二進制編碼
6)在硬盤上以何種編碼存的數據,必須以原來的編碼讀取,不然會亂碼

1.6.其餘地區的編碼字符集

BIG5 (1984):臺灣設計,13053個繁體中文
Shift-JIS,日本字符
ks_c_5601(1987),韓國字符
TIS-620,泰國編碼

1.7.ANSI編碼

1)不一樣的國家和地區制定了不一樣的標準,由此產生了 GB23十二、GBK、Big五、Shift_JIS 等各自的編碼標準。這些使用 1 至 4 個字節來表明一個字符的各類漢字延伸編碼方式,稱爲 ANSI 編碼

(American National Standards Institute美國國家標準學會)

2)在簡體中文Windows操做系統中,ANSI 編碼表明 GBK 編碼;
3)在日文Windows操做系統中,ANSI 編碼表明 Shift_JIS 編碼。
4)不一樣 ANSI 編碼之間互不兼容,當信息在國際間交流時,沒法將屬於兩種語言的文字,存儲在同一段 ANSI 編碼的文本中。 固然對於ANSI編碼而言,0x00~0x7F之間的字符,依舊是1個字節表明1個字符。這一點是ANSI編碼與Unicode編碼之間最大也最明顯的區別。

總結:

1)字符編碼的發展:

ASCII -->GB2312 ->GBK1.0(GBK)-->GB18030 
ASCII -->unicode -->utf-8/utf-16

2)不一樣字符編碼佔用的磁盤空間大小

1)ASCII碼中:一個英文字符(拉丁文)佔1個字節,8位,不能存中文,因此出了Unicode
2)GBK中:一箇中文字符佔用2個字節,1個英文字符佔用1個字節
3)unicode中:默認全部中英文字符都佔2個字節,16位,
4)utf-8中:一箇中文字符佔用3個字節,一個英文字符默認佔1個字節,8位

2.字符編碼的使用

2.1.Python解釋器中的字符編碼的使用

Python解釋器在加載 .py文件中的代碼時,須要使用指定的字符編碼將內容進行轉換爲0101這種二進制代碼,交付給CPU處理
Python2.x解釋器默認編碼是ASCII碼,不支持中文,要使用中文,需提早申明字符編碼
Python3.x解釋器默認編碼是unicode,支持中文,不須要申明字符編碼

Python2.7支持中文的方法:

1)編輯py程序msg.py,在第一行申明須要使用的字符編碼

vim msg.py
-------------------------
# -*- coding:utf-8 -*-       # 放在第一行;
# encoding:utf-8             # 放在第一行;
# coding:utf-8               # 放在第一行;
msg = "今每天氣真不錯"
print(msg)
-------------------------
python msg.py
--->今每天氣真不錯

也能夠用這種:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

2)變量值前加個字母「u」,表明用Unicode顯示

vim msg.py
-------------------------
msg = u"今每天氣真不錯"
print(msg)
-------------------------
python msg.py
--->今每天氣真不錯

2.2.系統中編碼的使用:

1)中文Windows默認編碼:GBK(GBK1.0)

切換字符編碼爲GBK的windows命令:

chcp 936

2)Mac和Linux默認編碼:UTF-8

3)打印系統默認編碼

import sys
print(sys.getdefaultencoding())

3.字符編碼轉換(py2和py3的編碼區別)

3.1.Python2中的string編碼

1)在Python2中,字符串能夠存成兩種類型:str和unicode,他們在內存中的存儲方式不一樣,但均可以直接打印到屏幕上

str存儲byte字節數據,用<type 'str'>表示,存入的是二進制bytes的str類型,打印到屏幕時會自動轉爲Unicode,因此能夠打印中文,也能夠手動轉換爲Unicode打印到屏幕
unicode存儲unicode數據,用<type 'unicode'>表示,直接保存成Unicode數據,能夠直接打印內存中的Unicode數據到屏幕,也能夠編碼爲str字符串打印出來
str1:UTF-8 --> str1.decode("utf-8") -->str1-2:Unicode --> str1-2.encode("gbk")-->str1-2:GBK
str2:GBK --> str2.decode("gbk") -->str2-2:Unicode --> str2-2.encode("utf-8") -->str2-2:UTF-8

2)兩種類型能夠經過編碼解碼進行相互轉換,也能夠進行字符串拼接(bytes數據會自動轉碼爲Unicode)

3)只要數據所有是ASCII,自動轉換就正常,不然會出現亂碼,出現UnicodeDecodeError 的錯誤
Python2編碼讓程序在處理 ASCII 的時候更加簡單,代價就是在處理非 ASCII 的時候將會失敗

實例演示1:

[root@zssrv ~]# python2
----------------------------
str1='中國hello123'
print type(str1)             # <type 'str'>,存入的是str類型
print repr(str1)             # '\xe4\xb8\xad\xe5\x9b\xbdhello123',內存中存儲的二進制bytes數據
print str1                # 中國hello123,打印到屏幕時會自動轉爲Unicode,因此能夠打印中文

a = str1.decode('utf8')        # str類型也就是二進制bytes,手動解碼成Unicode讀出來
print type(a)              # <type 'unicode'>,轉換爲了Unicode
print repr(a)                # u'\u4e2d\u56fdhello123',內存中存儲的Unicode數據
print  a                  # 中國hello123,手動轉換成的a是Unicode因此能夠打印中文
a2 = str1.decode('gbk')      # 但若是用錯誤的編碼解析,就會報錯
# --->UnicodeDecodeError: 'gbk' codec can't decode bytes in position 2-3: illegal multibyte sequence

str2=u'你好hello123'
print type(str2)            # <type 'unicode'>,直接保存成了Unicode數據
print str2                # 你好hello123,直接打印內存中的Unicode數據
print repr(str2)            # u'\u4f60\u597dhello123',內存中存儲的Unicode數據

b = str2.encode('utf-8')    # Unicode類型的,能夠編碼爲str讀出來
print b                     # 你好hello123
print type(b)               # <type 'str'>
print repr(b)               # '\xe4\xbd\xa0\xe5\xa5\xbdhello123'
---------------------------

實例演示2:字符串拼接

print (u"hello"+"world")     # hello中國
print ("hello"+u"中國")      # hello中國
print (u"hello"+"中國")
--->UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

3.2.Python3中的string編碼

1)在Python3中,字符串有兩種數據類型:str(unicode)和bytes,但內存中都表示爲Unicode,能夠直接打印到屏幕 

str類型存unicode數據,用<class 'str'>表示,使用」\uxxxx「顯示,也就是內存中的文本數據流
bytse類型存bytes字節數據,用<class 'bytes'>表示,使用b’\uxxxx’這種二進制格式顯示,也就是硬盤文本文件中的內容

2)在Python命令行中,Unicode字符會默認的轉換成可顯示的字符串格式,而不會顯示其自己的二進制碼。

3)Python 3最重要的新特性之一是對文本和二進制數據做了更爲清晰的區分,再也不會對bytes字節串進行自動解碼。
4)不能拼接字符串和字節包,不能在字節包裏搜索字符串(反之亦然),不能將字符串傳入參數爲字節包的函數(反之亦然)。

實例演示:Python3中

import json
str3 = '你好'
print(str3)                # 你好,能夠直接打印字符串
print(type(str3))             # <class 'str'>,在內存中保存成Unicode數據
print(json.dumps(str3))       # "\u4f60\u597d"

c = str3.encode('utf8')       # 能夠手動編碼爲bytes類型,二進制數據
print(c)                      # b'\xe4\xbd\xa0\xe5\xa5\xbd',直接打印二進制數據,而不是字符內容
print(type(c))                # <class 'bytes'>

u = c.decode('utf8')          # 再次用utf-8解碼爲str字符串類型(Unicode數據)
print(u)                      # 你好
print(type(u))                # <class 'str'>,查看是Unicode數據
print(json.dumps(u))          # "\u4f60\u597d"

str4 = u'你好'
print(str4)           # 你好,能夠直接打印,不必前面加u
print(type(str4))             # <class 'str'>
print(json.dumps(str4))       # "\u4f60\u597d"

實例演示:字符串拼接,不一樣類型,確定會報錯

print(b'hello'+'world')       # TypeError: can't concat str to bytes

注意:

1)在Python 2中,print是一個語句(statement);在Python 3中變成了函數(function)。
2)不管py2,仍是py3,與明文直接對應的就是unicode數據,打印unicode數據就會顯示相應的明文(包括英文和中文)
3)在內存中的unicode,存到硬盤上或網絡傳輸須要轉成gbk/utf-8(自動轉)
4)音視頻文件是用二進制bytes字節數據保存的
5)Python3裏只有Unicode纔會打印中文,s.encode("gbk")不會打印中文(不去編碼表裏找),而是顯示bytes數據

經過這種方式就是想告訴別人:py3裏想要看到字符,必須是Unicode,其餘的編碼一概按bytes格式展現

遇到亂碼問題的思路:

1)Python解釋器的默認編碼(py2,py3)
2)Python源文件文件編碼(申明的編碼utf-8,gbk)
3)Terminal使用的編碼(cmd等)與py文件的不匹配
4)操做系統的語言設置(windows,linux,mac等)

經常使用的編輯器默認編碼

EmEditor        GB2312
pycharm         unicode
notepad++       utf-8

參考文章:

python 之路,致那些年,咱們依然沒搞明白的編碼
http://www.cnblogs.com/alex3714/articles/7550940.html

py編碼終極版
http://www.cnblogs.com/yuanchenqi/articles/5956943.html

字符串相關
http://www.diveintopython3.net/strings.html

unicode與gbk的映射表
http://www.unicode.org/charts/

 

完畢,呵呵呵呵

相關文章
相關標籤/搜索