字符串的處理在數據清洗中占比很大。也就是說,很多不規則的數據處理都是在對字符串進行處理。Excel提供了拆分、提取、查找和替換等對字符串處理的技術。在Pandas中同樣提供了這些功能,并且在Pandas中還有正則表達式技術的加持,讓其字符串處理能力更加強大。
01、正則
正則就是正則表達式(Regular Expression)的簡稱,它是一種強大的文本處理技術。正則表達式描述了字符串匹配的模式(Pattern),可以用來檢查一個字符串是否含有某種子字符串,對匹配成功的字符串可以進行提取、拆分、查找和替換等處理。大部分的編程語言支持正則表達式,匹配規則也基本相同,但不同編程語言的處理方式略有不同。
在實際工作中,用戶需要的多條有用信息很可能會混雜在一起,要將這些雜亂的數據整理規范,很可能就需要正則表達式的加持。在Pandas中提供的很多關于文本處理的函數支持正則表達式,所以在講解Pandas的文本處理函數之前,首先要詳細了解正則表達式技術。
1●正則表達式的導入與創建
要在Python中使用正則表達式,首先要導入re庫,它是Python的內置庫,也就是說不需要用戶安裝; 接下來演示一下直接導入使用和通過編譯后再使用兩種方法。
1.直接導入使用
在導入re庫之后,直接使用re.函數()的方式來使用正則表達式,例如使用re.findall()函數,示例代碼如下:
import re #導入正則表達式庫
print (re.findall(r' d','9527') ) #直接調用正則表達式函數使用
print (re.findall(r' d','5201314')) #直接調用正則表達式函數使用
?運行結果如下:
2.通過編譯使用
如果需要重復使用一個正則表達式對象,則可以將正則表達式預編譯成正則表達式對象,這樣效率更高。在導入re庫后,將正則表達寫入re.compile()函數,然后生成正則表達式對象,再調用這個對象中的函數進行處理,示例代碼如下:
import re #導入正則表達式庫
pat=re.compile(r'\d') #使用 compile 函數生成正則表達式對象
print(pat.findall('5201314')) #調用編譯后的正則表達式對象中的函數使用
print (pat.findall('9527') ) #調用編譯后的正則表達式對象中的函數使用
?運行結果如下:
?
預編譯的方式也可以直接寫成一條代碼,如re.compile(r'\d').findall('9527')。不管正則表達式采用何種調用方式,始終脫離不了以下三要素。
(1) 正則表達式字符串。如r'\d',單引號中的字符串表明匹配規則,\d是查找單個數字的意思。
(2) 正則表達式被匹配的字符串。如'9527',對'9527'執行r'\d' 的匹配,意思就是查找'9527'中有多少個單數字。
(3) 匹配成功后的處理方式。例如調用findall()函數,表示如果匹配成功,則將查找出來的單個數字存儲在列表中。
在上面的三要素中,需要重點學習正則表達式字符串的編寫規則,以及匹配成功后的處理方式。
2●正則表達式處理函數
本來應該先講解正則表式的編寫規則,但讀者可能更希望正則表達式匹配成功后,能看到對應的處理結果,這樣能有更直觀的感受,所以本節先講解正則表達式的常用函數。
本節在講解正則表達式函數時,會分別講解直接寫法(re.函數())和預編譯寫法(regex.函數())兩種形式,雖然這兩種書寫形式對應的函數名一樣,功能也一樣,但函數的參數略有差異。
在Python的正則表達式中,使用不同函數,其返回的數據類型也不一樣,例如返回re.Match(匹配對象)、list(列表)、iterator(迭代器)、str(字符串)等,其中返回的re.Match匹配對象存儲有更多信息。
1. 從開始位置匹配(match()函數)
如果希望從字符串的開始位置匹配,則可以使用match()函數。如果匹配成功,則match()函數返回的是一個re.Match匹配對象。
1) re.match()函數
re.match()函數的參數說明如下。
re.match(pattern, string, flags=0)
pattern: 匹配的正則表達式。
string: 要匹配的字符串。
flags: 標志位,用于控制正則表達式的匹配方式,見表1。
■?表1 常見正則表達式flags的匹配模式
re.match()函數的示例代碼如下:
import re #導入正則表達式庫
print(re.match(r'apple','apple 蘋果') ) #在'apple 蘋果'字符串中以 apple'開頭
print (re.match(r'蘋果','apple 蘋果')) #在'apple 蘋果,字符串中以,蘋果'開頭
?運行結果如下:
2) regex.match()函數
regex.match()函數的參數說明如下。
regex.match(string[, pos[, endpos]])
string: 必選,被匹配的字符串。
pos: 可選,指定起始位置。
endpos: 可選,指定結束位置。
注意: regex為正則表達式對象的統稱。
regex.match()函數的示例代碼如下:
import re #導入正則表達式庫
print(re.compile(r'apple').match('apple 蘋果')) #在'apple 蘋果'字符串中以apple'開頭
print(re.compile(r'蘋果') .match('apple 蘋果')) #在'apple 蘋果,字符串中以,蘋果"開頭
?運行結果如下:
通過運行結果發現,第1個測試匹配成功,返回re.Match對象,其中span=(0, 5)表示匹配成功的字符串的起止位置。第2個測試沒有匹配成功,返回值為None。
還有一個與match()函數相似的fullmatch()函數,該函數完整匹配整個字符串。先演示一下re.fullmatch()函數,示例代碼如下:
import re #導入正則表達式庫
print (re.fullmatch(r'apple 蘋果',apple 蘋果')) #在 apple 蘋果'字符串中匹配apple 蘋果,
print (re.fullmatch (r'apple','apple 蘋果') ) #在 apple 蘋果,字符串中匹配
'apple'
?運行結果如下:
接下來演示regex.fullmatch()函數,示例代碼如下:
import re #導入正則表達式庫
print (re.compile(r'apple 蘋果').fullmatch('apple 蘋果')) #在'apple蘋果'字符串中匹配'apple 蘋果print(re.compile(r'apple') .fullmatch('apple 蘋果')) #在 apple 蘋果'字符串中匹配'apple
?運行結果如下:
通過上面的示例會發現,只有完整匹配了整個字符串,才能匹配成功,否則返回值為None,并且在示例中會發現,只有匹配的字符串與被匹配的字符串相等才可以成功。是不是匹配與被匹配的字符串一定要相等呢? 其實并非如此,可以寫更復雜的正則表達式字符串,只要從開頭到結尾都能匹配成功就可以。
2. 從任意位置匹配(search()函數)
match()函數必須從指定的起始位置開始匹配,如果希望從任意位置開始匹配,則可以使用search()函數。如果匹配成功,則返回re.Match配匹對象,否則返回值為None。
1) re.search()函數
re.search()函數的參數說明如下。
search(pattern, string, flags=0)
pattern: 匹配的正則表達式。
?
string: 要匹配的字符串。
flags: 標志位,用于控制正則表達式的匹配方式,見表6-1。
re.search()函數的示例代碼如下:
import re #導入正則表達式庫
print (re.search(r'apple',3 個apple蘋果')) #在3個apple 蘋果'字符串中搜索apple"
print(re.search(r'apple',apple 蘋果3 個')) #在3個apple 蘋果'字符串中搜索apple"
print (re.search(r'梨子','apple 蘋果3個')) #在'apple 蘋果3 個1字符串中搜索'梨子
運行結果如下:
2) regex.search()函數
regex.search()函數的參數說明如下。
regex.search(string[, pos[, endpos]])
string: 必選,被匹配的字符串。
pos: 可選,指定起始位置。
endpos: 可選,指定結束位置。
regex.search()函數的示例代碼如下:
?
import re#導入正則表達式庫
print(re.compile(r'apple').search('3 個apple蘋果')) #在3個apple蘋果'字符串中搜索'apple'
print(re.compile(r'apple').search('apple 蘋果3個')) #在3個apple蘋果'字符串中搜索'apple'
print(re.compile(r'梨子').search('apple 蘋果3個')) #在apple蘋果3 個1字符串中搜索,梨子|
運行結果如下:
通過上面的示例會發現,只要被搜索的字符串包含要查找的字符串,最后都能匹配成功,并且返回re.Match對象。
注意: match()函數和search()函數在進行匹配時,可能有多個對象符合匹配要求,但只返回第1個匹配成功的re.Match對象。
3. 用列表存儲匹配成功的值(findall()函數)
前面學習的match()函數和search()函數只返回第1次匹配成功的re.Match 對象,如果希望返回所有匹配成功的數據,則可以使用findall()函數,返回的結果是列表類型; 如果沒有匹配成功,則返回空列表。
注意,findall()函數匹配出的數據只是從re.Match對象中提取出的信息之一。
1) re.findall()函數
re.findall()函數的參數說明如下。
re.findall(pattern,string,flags=0)
pattern: 匹配的正則表達式。
string: 要匹配的字符串。
flags: 標志位,用于控制正則表達式的匹配方式,見表1。
re.findall()函數的示例代碼如下:
txt='張三2李四3 王五 4 陳小兵 15 大龍' #被匹配的字符串
print (re.findall(r' D+\d+',txt)) #常規匹配
print (re.findall(r'(\D+)\d+',txt))#添加 1 組括號
print (re.findall(r'(\D+) (\d+)',txt)) #添加 1組以上括號
?運行結果如下:
2) regex.findall()函數
regex.findall()函數的參數說明如下。
regex.findall(string[, pos[, endpos]])
string: 待匹配的字符串。
pos: 可選參數,指定字符串的起始位置,默認值為0。
endpos: 可選參數,指定字符串的結束位置,默認值為字符串的長度。
regex.findall()函數的示例代碼如下:
import re #導入正則表達式庫
txt='張三2李四3 王五 4 陳小兵 15 大龍' #被匹配的字符串
print (re.compile(r'\D+\d+') .findall(txt))#添加 1 組括號
print (re.compile(r'(\D+) d+') .findall(txt)) #常規匹配
print(re.compile(r'(\D+) (\d+)').findall(txt)) #添加1組以上括號
?運行結果如下:
通過上面的示例會發現,findall()函數如果沒有分組,則直接返回匹配成功的所有字符串; 如果只有1個分組,則將分組中的值返回到列表; 如果多于1個分組,則列表中的每個元素是元組,元組中的元素就是每個分組中的值。
注意: findall()函數中的正則表達式字符是'\D+\d+ ',表示匹配連續的非數字和連續的數字,后面在講解正則表達式元字符時,會詳細講解\D與\d。
4. 用迭代器存儲匹配成功對象(finditer()函數)
finditer()函數與findall()函數的功能類似,其主要區別在于findall()函數匹配成功后返回的是列表,列表中存儲的是匹配成功的數據; 而finditer()函數匹配成功后返回的是迭代器,迭代器中存儲的是匹配成功的re.Match對象。
1) re.finditer()函數
re.finditer()函數的參數說明如下。
re.finditer(pattern, string, flags=0)
pattern: 匹配的正則表達式。
string: 要匹配的字符串。
flags: 標志位,用于控制正則表達式的匹配方式,見表1。
re.finditer()函數的示例代碼如下:
import re #導入正則表達式庫
txt='張三2李四3 王五 4 陳小兵 15 大龍' #被匹配的字符串
print (re.finditer(r'\D+\d+',txt)) #常規匹配
print (re.finditer(r'( D+)\d+'txt)) #添加 1組括號
print (re.finditer(r'(\D+) (\d+)',txt)) :#添加 1 組以上括號
?運行結果如下:
2) regex.finditer()函數
regex.finditer()函數的參數說明如下。
regex.finditer(string[, pos[, endpos]])
string: 待匹配的字符串。
pos: 可選參數,指定字符串的起始位置,默認值為 0。
endpos: 可選參數,指定字符串的結束位置,默認值為字符串的長度。
regex.finditer()函數的示例代碼如下:
import re #導入正則表達式庫
txt='張三 2 李四3 王五 4 陳小兵 15 大龍' #被匹配的字符串
print (re.compile(r' D+ \d+') .finditer(txt))#常規匹配
print (re.compile(r'(\D+)\d+') .finditer(txt))print (re.compile(r'(\D+) #添加 1 組括號(\d+)').finditer(txt)) #添加1組以上括號
?運行結果如下:
通過上面的示例會發現,返回的是callable_iterator object(迭代器對象),迭代器中存儲的是每個匹配成功的re.Macth對象。也就是說finditer()函數與findall()函數相比而言,能獲取更多的信息。
finditer()函數匹配成功后,可以用循環語句讀取迭代器中的數據,也可以用list()函數對迭代器進行轉換,示例代碼如下:
import re #導入正則表達式庫
txt='張三2李四3 王五 4 陳小兵 15 大龍' #被匹配的字符串
print (list (re.compile(r'\D+\d+').finditer(txt))) #常規匹配
運行結果如下:
觀察運行結果可以發現,每次匹配成功后,返回的不是具體的值,而是re.Match對象。
02、文末送書
作為生產力工具,Python是當今極為流行的編程語言。Python編程逐漸成為一項通用能力,從小學生到各個行業的從業人員都在學Python。Python確實能夠在很多領域發揮作用,以至于Python編程已經成為一些職業的加分項甚至必備能力。
市面上的Python書繁多,新入行的朋友問的最多的問題就是如何挑選一本好的入門書?這真是個讓人很頭疼的問題!
-
知識點堆砌,雜而不精脫
-
離實際開發需求詳略
-
設置不合理
-
學習曲線過于陡峭
-
案例過于炫技
-
不注重學習過程和結果
以上是Python入門書的通病,今天推薦的這本《Python之光》,將重新定義Python學習:
?參與方式:文章三連并評論“零基礎學習Python,就用《Python之光》”參與抽獎,48小時后,評論區自動抽取5位幸運小伙伴每人送出1本(包郵到家哦)!
?