Python中的文本和字節序列

導語:本文章記錄了本人在學習Python基礎之數據結構篇的重點知識及我的心得,打算入門Python的朋友們能夠來一塊兒學習並交流。

本章重點html

一、瞭解字符字節等概念,編解碼問題;
二、熟悉字符的規範化處理和雙模式API。

1、基本概念

  1. Unicode
    Unicode(統一碼、萬國碼、單一碼)是計算機科學領域裏的一項業界標準,包括字符集、編碼方案等。Unicode 是爲了解決傳統的字符編碼方案的侷限而產生的,它爲每種語言中的每一個字符設定了統一而且惟一的二進制編碼,以知足跨語言、跨平臺進行文本轉換、處理的要求。

  2. 來自英文bit,音譯爲「比特」,表示二進制位。位是計算機內部數據儲存的最小單位,11010100是一個8位二進制數。一個二進制位只能夠表示0和1兩種狀態(21);兩個二進制位能夠表示00、0一、十、11四種(22)狀態;三位二進制數可表示八種狀態(23)。
  3. 字節
    字節是計算機中數據處理的基本單位。計算機中以字節爲單位存儲和解釋信息,規定一個字節由八個二進制位構成,即1個字節等於8個比特(1Byte=8bit)。八位二進制數最小爲00000000,最大爲11111111;一般1個字節能夠存入一個ASCII碼,2個字節能夠存放一個漢字國標碼。

  4. 計算機進行數據處理時,一次存取、加工和傳送的數據長度稱爲字(word)。一個字一般由一個或多個(通常是字節的整數位)字節構成。例如286微機的字由2個字節組成,它的字長爲16;486微機的字由4個字節組成,它的字長爲32位機。
  5. 字長
    字長是指cpu的每一個字所包含的位數。根據計算機的不一樣,字長有固定的和可變的兩種。固定字長,即字長度不論什麼狀況都是固定不變的;可變字長,則在必定範圍內,其長度是可變的。計算的字長是指它一次可處理的二進創數字的數目。計算機處理數據的速率,天然和它一次能加工的位數以及進行運算的快慢有關。若是一臺計算機的字長是另外一臺計算機的兩倍,即便兩臺計算機的速度相同,在相同的時間內,前者能作的工做是後者的兩倍。
  6. 碼位
    又稱字符的標識。在Unicode標準中以4~6個十六進制數字表示,並加前綴「U+」。例如字母A的碼位是U+0041
  7. 編碼
    把碼位轉換成字節序列,調用s.encode()
  8. 解碼
    把字節序列轉換成碼位,調用s.decode()

編解碼例子:python

s="São Paulo"
a=s.encode('utf8')
print(a)#b'S\xc3\xa3o Paulo'
b=a.decode("utf8")
print(b)
output:São Paulo

2、編解碼問題

一、編解碼器

  • latin1( 即 iso8859_1)
    一種重要的編碼, 是其餘編碼的基礎。 例如 cp1252 和Unicode( 注意, latin1 與 cp1252 的字節值是同樣的, 甚至連碼位也相同) 。
  • cp1252
    Microsoft 制定的 latin1 超集, 添加了有用的符號, 例如彎引號和€( 歐元) ; 有些 Windows 應用把它稱爲「ANSI」, 但它並非 ANSI 標準。
  • cp437
    IBM PC 最初的字符集, 包含框圖符號。 與後來出現的 latin1 不兼容。
  • gb2312
    用於編碼簡體中文的陳舊標準; 這是亞洲語言中使用較普遍的多字節編碼之一。
  • utf-8
    目前 Web 中最多見的 8 位編碼; 與 ASCII 兼容( 純 ASCII 文本是有效的 UTF-8 文本) 。
  • utf-16le
    UTF-16 的 16 位編碼方案的一種形式; 全部 UTF-16 支持經過轉義序列( 稱爲「代理對」, surrogate pair) 表示超過 U+FFFF 的碼位。

二、瞭解編解碼問題

瞭解有關Unicode錯誤的處理方法。正則表達式

2.1 UnicodeEncodeError

編碼出現的錯誤在於編碼器可能沒法對字符串編碼,以中英文字符串爲例:編程

city="DaLian大連"
print(city.encode("utf8"))#b'DaLian\xe5\xa4\xa7\xe8\xbf\x9e'
print(city.encode("iso8859_1"))

輸出報錯:網絡

Traceback (most recent call last):
  File "D:\韓文承\編程工做空間\Fluent Python\section4-1.py", line 10, in <module>
    print(city.encode("iso8859_1"))
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 6-7: ordinal not in range(256)

緣由在於這個latin1不會對中午編碼,因此咱們須要處理這個EncodeError,處理以下:數據結構

print(city.encode("iso8859_1",errors="ignore"))#b'DaLian'
print(city.encode("iso8859_1",errors="replace"))#b'DaLian??'
print(city.encode("iso8859_1",errors="xmlcharrefreplace"))#b'DaLian&#22823;&#36830;'
  • errors="ignore"
    跳過沒法編碼的字符,這樣作一般不妥。
  • errors="replace"
    用問號替代沒法編碼的字符,雖然損壞了數據,但用戶收到了編碼有問題的信號。
  • errors="xmlcharrefreplace"
    用xml實體代替沒法編碼的字符。

想了解更多錯誤處理方式可查閱Python官方Library:
https://docs.python.org/3/lib...編輯器

2.2 UnicodeDecodeError

解碼出現的錯誤在於陳舊的解碼器能解碼任何字節序列而不拋出錯誤,有時會解碼出無用的、亂碼的字符。以包含變音符號的字節序列爲例:函數

c=b"Montr\xe9al"
print(c.decode("iso8859_1"))#Montréal
print(c.decode("cp1252"))#Montréal
print(c.decode("cp437"))#MontrΘal 輸出已經有問題了
print(c.decode("koi8_r"))#MontrИal KOI8_R是編碼俄文的,此處輸出了俄文字母
print(c.decode("utf8"))

報錯:學習

Traceback (most recent call last):
  File "D:\韓文承\編程工做空間\Fluent Python\section4-1.py", line 19, in <module>
    print(c.decode("utf8"))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 5: invalid continuation byte

緣由在於utf_8檢測到c不是有效utf_8字符串,拋出UnicodeDecodeError。處理以下:網站

print(c.decode("utf8",errors="replace"))#Montr�al。用�替代沒法解碼的字節

2.3 SyntaxError

若是加載的模塊中包含utf_8以外的數據,那麼解釋器會報錯SyntaxError。

三、Chardet

Chardet是Python的一個庫,能夠檢測出未知字節序列的編碼方式。
不要在二進制模式中打開文本文件。即便想判斷編碼,也該用Chardet!

四、BOM(byte-order mark)

字節序標記,這個標記針對非單字節非字符串外的其他數據(如short,int)指明字節存儲的方式,具體分爲大端存儲和小端存儲。
大端存儲第一個字節是高位,容易判斷數值的正負;
小端存儲第一個字節是地位,容易進行數值的運算。
須要注意:TCP/IP協議規定網絡字節序爲大端字節序。這意味着主機字節序若是是小端存儲必須轉化爲大端字節序才能經過網絡發送數據。
To Learn More:https://zhuanlan.zhihu.com/p/...

3、文本處理

一、處理文本文件

編碼默認值
在多系統處理文件時應顯式制定編碼,不然容易出現默認編碼器沒法解碼字節序列的狀況。
編輯器默認編碼查詢:locale.getpreferredencoding()#cp936

Unicode三明治原則
咱們能夠用一個簡單的原則處理編碼問題: 字節序列->字符串->字節序列。就是說程序中應當僅處理字符串,當須要保存到文件系統或者傳輸的時候,編碼爲字節序列。

二、規範化處理

Unicode字符串規範化
碼位規範化函數:unicodedata.normalize(格式,字符串)
格式參數:

  • NFC:使用最少的碼位構造等價字符串
  • NFD :使用基字符和組合字符構造等價字符串
  • NFKC 和NFKD:將兼容字符分解

對大多數應用來講NFC是最好的規範化形式。

from unicodedata import normalize
d="café"
e="cafe\u0301"
print(normalize("NFC",d)==normalize("NFC",e))#True
print(normalize("NFD",d)==normalize("NFD",e))#True

規範化以後兩個不一樣的碼位相等的。
保存文件以前最好用規範化函數unicodedata.normalize(「NFC」,字符串)清洗字符串

大小寫摺疊函數:str.casefold()
自Python3.4起,str.lower()和str.casefold()不一樣的結果有116個碼位,佔Unicode命名的總字符的0.11%

三、文本排序

Unicode 排序:unicode collation algorithm, UCA 使用 PyUCA 庫。
下載地址:https://pypi.python.org/pypi/...

4、雙模式API

雙模式是指標準庫中一些函數可以接受字符串或字節序列爲參數,並根據類型進行處理。
API(Application Programming Interface)即應用程序接口。能夠把 API 理解爲一個軟件組件或是一個 Web 服務與外界進行的交互的接口。通俗的理解是程序和程序之間的交互,交互就是傳遞數據,觸發功能。

一、re模塊:構建正則表達式處理字符串。

正則表達式:能夠匹配文本片斷的模式。

1.1語法介紹:

通配符:

  • .點dot:可以匹配任意的字符。
  • ^尖號:從開始匹配,意味着開始的字符必須和partern一致方可匹配上,不然匹配返回none.。
  • $美圓符號:從尾部開始匹配,尾部開始的字符必須和partern一致方可匹配上,不然匹配返回none.。
  • *星號:容許模式重複0次或屢次。
  • +加號:容許模式重複1次或屢次。
  • ?問號:容許模式重複0次或1次。
  • {m,n}:容許模式重複m~n次。(貪婪匹配下直接匹配到n次)當m=n即爲{m},只匹配m次。

用反斜線對特殊符號進行轉義:
有時咱們只想用特殊符號如dot「."的字面意思,而非做爲通配符使用。例如匹配網站」baidu.com「中的點就須要轉義,變成"baidu\.com",即只匹配」baidu.com「
字符集:
表示欲匹配字符的集合,相比較通配符中的點號而言範圍更小一些。例如[0-9A-F]能夠匹配一個十六進制的字符。
注意:一個字符集只能匹配一個字符,除非配合數量限定符使用!
預約義字符集

  • d,數字[0-9]
  • D,非數字[^\d]
  • s,空白字符,包括空格,trnfv
  • S,非空白字符[^\s]
  • w,單詞字符[A-Za-z0-9_]
  • W,非單詞字符[^\w]

選擇符和子模式:
此項欲匹配的範圍比字符集還要小。好比你只想匹配python和people這兩個單詞,就能夠用管道符號(|),即「python|people"。
若是操做的不是整個模式partern而是模式的一部分,圓括號括起來的部分稱做子模式,即「p(ython|eople)」

1.2重要的函數:

函數 描述
re.compile(pattern, flags=0) 根據正則表達式的字符串建立模式對象
re.search(pattern, string, flags=0) 在字符串中尋找模式
re.match(pattern, string, flags=0) 在字符串的開始處匹配模式
re.split(pattern, string, maxsplit=0, flags=0) 根據模式的匹配項來分割字符串
re.findall(pattern, string, flags=0) 列出字符串中模式的全部匹配項
re.finditer(pattern, string, flags=0) 返回一個迭代器,其中包含知足正則表達式要求的match objects
re.sub(pattern, repl, string, count=0, flags=0) 將字符串中全部pat的匹配項用repl替換

re.escape(pattern) 將字符串中全部特殊正則表達式字符轉義
Tips:re.compile構建模式,對於重複式的匹配效率更高。
flags參數介紹:

  • re.I 或re.IGNORECASE
    使匹配忽略字母大小寫。
  • re.L或re.LOCALE
    影響 「w, 「W, 「b, 和 「B,這取決於當前的本地化設置。
  • re.M或re.MULTILINE
    使用本標誌後,‘^’和‘$’匹配行首和行尾時,會增長換行符以前和以後的位置。
  • re.S或re.DOTALL
    使點號這個特殊字符徹底匹配任何字符,包括換行;沒有這個標誌, 「.」 匹配除了換行符外的任何字符。
  • re.X或re.VERBOSE
    當該標誌被指定時,在 RE 字符串中的空白符被忽略,除非該空白符在字符類中或在反斜槓以後。它也能夠容許你將註釋寫入 RE,這些註釋會被引擎忽略;註釋用 「#」號 來標識,不過該符號不能在字符串或反斜槓以後。

1.3MatchObject對象

MatchObject是一次成功匹配後返回的對象類型,它支持以下的重要方法:

  • group([group1, …]):
    得到一個或多個分組截獲的字符串;指定多個參數時將以元組形式返回。group1可使用編號也可使用別名;編號0表明整個匹配的子串;不填寫參數時,返回group(0);沒有截獲字符串的組返回None;截獲了屢次的組返回最後一次截獲的子串。
  • groups():
    以元組形式返回所有分組截獲的字符串。至關於調用group(1,2,…last)。
  • start([group]):
    返回指定的組截獲的子串在string中的起始索引(子串第一個字符的索引)。group默認值爲0。
  • end([group]):
    返回指定的組截獲的子串在string中的結束索引(子串最後一個字符的索引+1)。group默認值爲0。
  • span([group]):
    返回(start(group), end(group))。

1.4貪婪和非貪婪模式

*和+這類數量限定符默認是貪婪的,即儘量多的匹配知足要求的字符串。只有在其後加上問號?方可變成非貪婪的。
貪婪與非貪婪eg:

import re 
greedy=re.compile(r"<.*>")#貪婪
non_greedy=re.compile(r"<.*?>")#非貪婪,利用問號限制
print(greedy.search("<H1>Chapter 1 - 介紹正則表達式</H1>"))
print(non_greedy.search("<H1>Chapter 1 - 介紹正則表達式</H1>"))

輸出:

<_sre.SRE_Match object; span=(0, 28), match='<H1>Chapter 1 - 介紹正則表達式</H1>'>
<_sre.SRE_Match object; span=(0, 4), match='<H1>'>

對字符串和字節序列進行re匹配:

import re 
text_str = "Ramanujan saw \u0be7\u0bed\u0be8\u0bef as 1729 = 1³ + 12³ = 9³ + 10³."
text_byte=text_str.encode('utf_8')

str_number=re.compile(r"\d+")
str_word=re.compile(r"\w+")
byte_number=re.compile(rb"\d+")
byte_word=re.compile(rb"\w+")

print("str_number",str_number.findall(text_str))
print("str_word",str_word.findall(text_str))
print("byte_number",byte_number.findall(text_byte))
print("byte_word",byte_word.findall(text_byte))

輸出:

str_number ['௧௭௨௯', '1729', '1', '12', '9', '10']
byte_number [b'1729', b'1', b'12', b'9', b'10']
str_word ['Ramanujan', 'saw', '௧௭௨௯', 'as', '1729', '1³', '12³', '9³', '10³']
byte_word [b'Ramanujan', b'saw', b'as', b'1729', b'1', b'12', b'9', b'10']

分析:經過分別對字符串和字節序列進行數字、單詞字符的匹配操做,容易發現對字節序列的匹配僅限於ASCII中的數字和單詞字符,而對字符串的匹配會包含更多的泰米爾數字和上標等其餘字符。
To Learn More: https://docs.python.org/3/lib...

二、os模塊:

  • os.listdir() :

用於返回指定的文件夾包含的文件或文件夾的名字的列表。這個列表以字母順序。

  • os.fsencode(filename):

若是 filename 是 str 類型或bytes 類型,使用sys.getfilesystemencoding() 返回的編解碼器把 filename 編碼成字節序列; 不然, 返回未經修改的 filename 字節序列。

  • os.fsdecode(filename):

若是 filename 是 bytes 類型或 str 類型, 使用sys.getfilesystemencoding() 返回的編解碼器把 filename 解碼成字符串; 不然, 返回未經修改的 filename 字符串。

相關文章
相關標籤/搜索