Python中的文字對象
Python 3.x中處理文字的對象有str, bytes, bytearray。
bytes和bytearray可以使用除了用作格式化的方法(format, format_map)以及幾個特殊的基於Unicode的方法(casefold, isdecimal, isidentifier, isnumeric, isPRintable, encode)以外幾乎所有str的方法。
bytes有一個類方法,可以通過序列來構建字串,而這個方法不可以用在str上。
>>> b = bytes.fromhex('E4 B8 AD')
>>> b
b'\xe4\xb8\xad'
>>> b.decode('utf-8')
'中'
>>> str(b)
"b'\\xe4\\xb8\\xad'"
Unicode和字元轉換
採用chr可以把一個Unicode的code point轉換為字元,通過ord可以進行反向操作。
>>> ord('A')
65
>>> ord('中')
20013
>>> chr(65)
'A'
>>> chr(20013)
'中'
lenFunction Compute的是字元數,不是位元組數
>>> len('中')
1
>>> '中'.encode('utf-8')
b'\xe4\xb8\xad'
>>> len('中'.encode('utf-8')) #計算的是bytes對象的長度,包含3個整數字元
3
Python與編碼
Python內部處理編碼的方式
在Python接受我們的輸入時,總是會先轉為Unicode。而且這個過程越早越好。
然後Python的處理總是對Unicode進行的,在這個過程中,一定不要進行編碼轉換的工作。
在Python向我們返回結果時,總是會從Unicode轉為我們需要的編碼。而且這個過程越晚越好。
Python源碼的編碼方式
Python預設使用utf-8編碼。
如果想使用一種不同的編碼方式來儲存Python代碼,我們可以在每個檔案的第一行或者第二行(如果第一行被hash-bang命令佔用了)放置編碼聲明(encoding declaration)
# ‐*‐ coding: windows‐1252 ‐*‐
Python中使用的編碼
C:\Users\JL>chcp #尋找作業系統使用的編碼
Active code page: 936
>>> import sys, locale
>>> locale.getpreferredencoding() #這個是最重要的
'cp936'
>>> my_file = open('cafe.txt','r')
>>> type(my_file)
<class '_io.TextIOWrapper'>
>>> my_file.encoding #檔案對象預設使用locale.getpreferreddecoding()的值
'cp936'
>>> sys.stdout.isatty(), sys.stdin.isatty(), sys.stderr.isatty() #output是否是控制台console
(True, True, True)
>>> sys.stdout.encoding, sys.stdin.encoding, sys.stderr.encoding #sys的標準控制流程如果被重新導向,或者定向到檔案,那麼編碼將使用環境變數PYTHONIOENCODING的值、控制台console的編碼、或者locale.getpreferredencoding()的編碼,優先順序依次減弱。
('cp936', 'cp936', 'cp936')
>>> sys.getdefaultencoding() #如果Python需要把位元據轉為字元對象,那麼在預設情況下使用該值。
'utf-8'
>>> sys.getfilesystemencoding() #Python用來編碼或者解碼檔案名稱(不是檔案內容)的時候,預設使用該編碼。
'mbcs'
以上是在Windows中的測試結果,如果在GNU/linux或者OSX中,那麼所有的結果都是UTF-8.
關於mbcs和utf-8的區別,可以參考http://stackoverflow.com/questions/3298569/difference-between-mbcs-and-utf-8-on-windows
檔案讀寫的編碼
>>> pen('cafe.txt','w',encoding='utf-8').write('café')
4
>>> fp = open('cafe.txt','r')
>>> fp.read()
'caf茅'
>>> fp.encoding
'cp936'
>>> open('cafe.txt','r', encoding = 'cp936').read()
'caf茅'
>>> open('cafe.txt','r', encoding = 'latin1').read()
'cafÃ'
>>> fp = open('cafe.txt','r', encoding = 'utf-8')
>>> fp.encoding
'utf-8'
從上面的例子可以看出,無論什麼時候都不要使用預設的編碼,因為在不同的機器上啟動並執行時候會出現意想不到的問題。
Python如何處理來自Unicode的麻煩
Python總是通過code point來比較字串的大小,或者是否相等的。
Unicode中重音符號有兩種表示方法,用一個位元組表示,或者用基字母加上重音符號表示,在Unicode中他們是相等的,但是在Python中由於通過code point來比較大小,所以就不相等了。
>>> c1 = 'cafe\u0301'
>>> c2 = 'café'
>>> c1 == c2
False
>>> len(c1), len(c2)
(5, 4)
解決方案是通過unicodedata庫中的normalize函數,該函數的第一個參數可以接受"NFC",'NFD','NFKC','NFKD'四個參數中的一個。
NFC(Normalization Form Canonical Composition):以標準等價方式來分解,然後以標準等價重組之。若是singleton的話,重組結果有可能和分解前不同。儘可能的縮短整個字串的長度,所以會把'e\u0301'2個位元組壓縮到一個位元組'é'。
NFD(Normalization Form Canonical Decomposition):以標準等價方式來分解
NFKD(Normalization Form Compatibility Decomposition):以相容等價方式來分解
NFKC(Normalization Form Compatibility Composition):以相容等價方式來分解,然後以標準等價重組之。
NFKC和NFKD可能會引起資料損失。
from unicodedata import normalize
>>> c3 = normalize('NFC',c1) #把c1往字串長度縮短的方向操作
>>> len(c3)
4
>>> c3 == c2
True
>>> c4 = normalize('NFD',c2)
>>> len(c4)
5
>>> c4 == c1
True
西方的鍵盤通常會鍵入儘可能短的字串,也就是說和"NFC"的結果一致,但是通過"NFC"來操作一下再比較字串是否相等比較安全。且W3C建議使用"NFC"的結果。
同樣的一個字元在Unicode中有兩個不同的編碼。
該函數會把一個單一的Unicode字元轉為另一個Unicode字元。
>>> o1 = '\u2126'
>>> o2 = '\u03a9'
>>> o1, o2
('Ω', 'Ω')
>>> o1 == o2
False
>>> name(o1), name(o2)
('OHM SIGN', 'GREEK CAPITAL LETTER OMEGA')
>>> o3 = normalize('NFC',o1)
>>> name(o3)
'GREEK CAPITAL LETTER OMEGA'
>>> o3 == o2
True
又比如
>>> u1 = '\u00b5'
>>> u2 = '\u03bc'
>>> u1,u2
('µ', 'μ')
>>> name(u1), name(u2)
('MICRO SIGN', 'GREEK SMALL LETTER MU')
>>> u3 = normalize('NFKD',u1)
>>> name(u3)
'GREEK SMALL LETTER MU'
再一個例子
>>> h1 = '\u00bd'
>>> h2 = normalize('NFKC',h1)
>>> h1, h2
('½', '1⁄2')
>>> len(h1), len(h2)
(1, 3)
有時候我們希望使用不區分大小寫形式進行比較
使用方法str.casefold(),該方法會把大寫字母轉換為小寫進行比較,比如'A'會轉為'a','MICRO SIGN'的'µ'會轉換為'GREEK SMALL LETTER MU'的'µ'
在絕大部分(98.9%)情況下str.casefold()和str.lower()的結果一致。
文字排序
由於不同的語言規則,如果單純按照Python的比較code point的方式進行,那麼會出現很多不是使用者期望的結果。
通常採用locale.strxfrm進行排序。
>>> import locale
>>> locale.setlocale(locale.LC_COLLATE,'pt_BR.UTF-8')
'pt_BR.UTF-8'
>>> sort_result = sorted(intial, key = locale.strxfrm)
編碼解碼錯誤
如果是Python源碼中出現瞭解碼錯誤,那麼會產生SyntaxError異常。
其他情況下,如果發現編碼解碼錯誤,那麼會產生UnicodeEncodeError, UnicodeDecodeError異常。
幾個摘自fluent python中的有用方法
from unicodedata import normalize, combining
def nfc_equal(s1, s2):
'''return True if string s1 is eual to string s2 after normalization under "NFC" '''
return normalize("NFC",s1) == normalize("NFC",s2)
def fold_equal(s1, s2):
'''return True if string s1 is eual to string s2 after normalization under "NFC" and casefold()'''
return normalize('NFC',s1).casefold() == normalize('NFC',s2).casefold()
def shave_marks(txt):
'''Remove all diacritic marks
basically it only need to change Latin text to pure ASCII, but this func will change Greek letters also
below shave_latin_marks func is more precise'''
normal_txt = normalize('NFD',txt)
shaved = ''.join(c for c in normal_txt if not combining(c))
return normalize('NFC',shaved)
def shave_latin_marks(txt):
'''Remove all diacritic marks from Latin base characters'''
normal_txt = normalize('NFD',txt)
keeping = []
latin_base=False
for c in normal_txt:
if combining(c) and latin_base:
continue #Ingore diacritic marks on Latin base char
keeping.append(c)
#If it's not combining char, it should be a new base char
if not combining(c):
latin_base = c in string.ascii_letters
編碼探嗅Chardet
這是Python的標準模組。
參考資料:
http://blog.csdn.net/tcdddd/article/details/8191464
以上就是python與編碼的內容,更多相關文章請關注topic.alibabacloud.com(www.php.cn)!