6.1 正則表達式的概念
正則表達式是用來簡潔表達一組字符串的表達式
正則表達式的優勢:簡潔
能非常簡單的表達一組數據的特徵,能將一組字符串的特點表達出來
- 通用的字符串表達框架
- 簡潔表達一組字符串的表達式
- 針對字符串表達“簡潔”和“特徵”思想的工具
- 判斷某字符串的特徵歸屬
正則表達式在文本處理中十分常用
- 表達文本類型的特徵(病毒、入侵等)
- 同時查找或替換一組字符串
- 匹配字符串的全部內容(主要)
正則表達式的使用
- 編譯:將符合正則表達式語法的字符串轉換成正則表達式的特徵
我們可以認爲編譯後的特徵與一組字符串 是對應的,而編譯前的正則表達式只是一個符合正則表達式語法的一組字符串,但並不是真正意義上的正則表達式
6.2 正則表達式的語法
正則表達式語法由字符和操作符構成
操作符 | 說明 | 實例 |
---|---|---|
. | 表示任何單個字符 | |
[ ] | 字符集,對單個字符給出取值範圍 | [abc]表示a、b、c,[a-z]表示a到z單個字符 |
[ ^ ] | 非字符集,對單個字符給出排除範圍 | [^abc]表示非a或b或c的單個字符串 |
* | 前一個字符0次或者無限次擴展 | abc表示ab、abc、abcc、等 |
+ | 前一個字符1次或無限次擴展 | abc+表示abc、abcc、abccc等 |
? | 前一個字符0次或者 1次擴展 | abc表示ab、abc |
| | 左右表達式任意一個 | abc|def表示abc、def |
{m} | 擴展前一個字符m次 | ab{2}c表示abbc |
{m,n} | 擴展前一個字符m至n次(含n) | ab{1,2}表示abc、abbc |
^ | 匹配字符串開頭 | ^abc表示abc且在一個字符串的開頭 |
$ | 匹配字符串結尾 | abc$表示abc且在一個字符串的結尾 |
() | 分組標記,內部只能用 | 操作符 | (abc)表示 abc,(abc |
\d | 數字,等價於[0-9] | |
\w | 單詞字符,等價於[A-Za-z0-9_] |
6.3 Re庫的基本使用
Re庫主要用於字符串匹配
調用方式:
import re
6.3.1正則表達式的表示類型
- raw string類型(原生字符串類型)
- string類型,更繁瑣。
注: 建議當正則表達式包含轉義符時使用raw string
6.3.2Re庫主要功能函數
函數 | 說明 |
---|---|
re.search() | 在一個字符串中搜索匹配正則表達式的第一個位置,返回match對象 |
re.match() | 從一個字符串的開始位置起匹配正則表達式,返回match對象 |
re.findall() | 搜索字符串,以列表類型返回全部能匹配的子串 |
re.split() | 將一個字符串按照正則表達式匹配結果進行分割,返回列表類型 |
re.finditer() | 搜索字符串,返回一個匹配結果的迭代類型,每個迭代元素時match對象 |
re.sub() | 在一個字符串中替換所有匹配正則表達式的子串,返回替換後的字符串 |
- re.search(pattern,string,flags=0)
- pattern:正則表達式的字符串或原生字符串表示
- string:待匹配字符串
- flags:正則表達式使用時的控制標記
常用標記 | 說明 |
---|---|
re.I re.IGNORECASE | 忽略正則表達式的大小寫,[A-Z]能夠匹配小寫字符 |
re.M re.MULTILINE | 正則表達式中的^操作符 能夠將給定字符串的每行當做匹配開始 |
re.S re.DOTALL | 正則表達式中的.操作符 能夠匹配所有字符,默認匹配除換行外的所有字符 |
import re
match = re.search(r'[1-9]\d{5}','BIT 100081')
if match:
print(match.group(0))
#100081
- group和groups
group()在正則表達式中用於獲取分段截獲的字符串,解釋如下代碼(代碼來自網絡)
import re
pattern = re.compile(r"([a-z]+) ([0-9]+)",re.I)
m = pattern.match("hello 2019 Hello 2018")
print(m.group(0))#hello 2019
print(m.group(1))#hello
print(m.group(2))#2019
#print(m.group(3))
print(m.group())#hello 2019
- 正則表達式中的三組括號把匹配結果分成三組
group() 同group(0)就是匹配正則表達式整體結果
group(1) 列出第一個括號匹配部分,group(2) 列出第二個括號匹配部分,group(3) 列出第三個括號匹配部分。 - 沒有匹配成功的,re.search()返回None
- 如果正則表達式中沒有括號,group(1)就不對了。
- 一般,m.group(N) 返回第N組括號匹配的字符
- m.groups() 返回所有括號匹配的字符,以tuple格式。 m.groups() == (m.group(0), m.group(1), …)
- re.match(pattern,string,flags=0)
從一個字符串的開始位置期匹配正則表達式,返回match對象
import re
match = re.match(r'[1-9]\d{5}','BIT 100081')
if match:
match.group(0)
print(match.group(0))
#AttributeError: 'NoneType' object has no attribute 'group'
match = re.match(r'[1-9]\d{5}','100081 BIT')
if match:
print(match.group(0))
#'100081'
- re.findall(pattern,string,flags=0)
搜索字符串,以列表類型返回全部能匹配的子串
import re
ls = re.findall(r'[1-9]\d{5}','BIT100081 TSU100084')
print(Is)
#['100081', '100084']
- re.split(pattern,string,maxsplit=0,flags=0)
將一個字符串按照正則表達式匹配結果進行分割,返回列表類型 - maxsplit:最大分割數,剩餘部分作爲最後一個元素輸出
import re
print(re.split(r'[1-9]\d{5}','BIT100081 TSU100084',maxsplit=1))
#['BIT', ' TSU100084']
print(re.split(r'[1-9]\d{5}','BIT100081 TSU100084',maxsplit=2))
#['BIT', ' TSU', '']
print(re.split(r'[1-9]\d{5}','BIT100081 TSU100084',maxsplit=3))
#['BIT', ' TSU', '']
print(re.split(r'[1-9]\d{5}','BIT100081 TSU100084'))
#['BIT', ' TSU', '']
- re.finditer(pattern,string,flags=0)
搜索字符串,返回一個匹配結果的迭代類型,每個迭代元素時match對象
import re
for m in re.finditer(r'[1-9]\d{5}','BIT100081 TSU100084'):
if m:
print(m.group(0))
# 100081
# 100084
-
re.sub(pattern,repl,string,count=0,flags=0)
在一個字符串中替換所有匹配正則表達式的子串,返回替換後的字符串簡單說就是用一個新的字符串替換正則表達式匹配上的字符串,並與原來的字符串經組合返回一個新的字符串
- repl:替換匹配字符串的字符串(當pattern匹配上某一個字符串後,替換的那個字符串)
- count:匹配的最大替換次數
import re
print(re.sub(r'[1-9]\d{5}',':zipcode','BIT100081 TSU100084'))
#'BIT:zipcode TSU:zipcode'
6.3.3Re庫的另一種等價用法
這種方法的好處就是經過一次編譯當我們需要多次對正則表達式進行使用和匹配時候可以使用這個方式加快程序的運行
- re.compile(pattern,flags=0)
將正則表達式的字符串形式編譯成正則表達式對象 - pattern:正則表達式的字符串或原生字符串表示
- flags:正則表達式使用時的控制標記
regex=re.compile(r'[1-9]\d{5}')
字符串或原生字符串表示並不是正則表達式,他只是一種表示,如果通過compile編譯生成了一個對象regex,這個regex纔是正則表達式,它代表了一組字符串,所以我們可以通過這樣的函數來實現正則表達式、表示之間的對應,而這種對應,使得我們能夠更好的理解正則表達式對象的這種使用方式,經過了compile之後的正則表達式,就可以使用它的對象的方法,而這個對象的方法與RE庫提供的6個操作方法是一致的
regex.search()
regex.match()
regex.findall()
regex.split()
regex.finditer()
regex.sub()
在這6個函數使用的過程中,需要注意,正是由於前面已經給了regex正則表達式對象,所以在調用這些函數的時候,需要將其中的正則表達式那個參數去掉,因爲我們已經不再需要正則表達式的參數,只需要直接給出相關的需要匹配的字符串就可以了
6.4 Re庫的match對象
match對象就是一次匹配的結果,它包含了很多匹配的相關信息
import re
match = re.search(r'[1-9]\d{5}','BIT 100081')
if match:
print(match.group(0))#100081
print(type(match))#<class 're.Match'>
- Match對象的屬性
屬性 | 說明 |
---|---|
.string | 待匹配的文本 |
.re | 匹配時使用的pattern對象(正則表達式) |
.pos | 正則表達式搜索文本的開始位置 |
.endpos | 正則表達式搜索文本的結束位置 |
- Match對象的方法
方法 | 說明 |
---|---|
.group(0) | 獲得匹配後的字符串 |
.start() | 匹配字符串在原始字符串的開始位置 |
.end() | 匹配字符串在原始字符串的結束位置 |
.span() | 返回(.start(),.end()) |
import re
m = re.search(r'[1-9]\d{5}','BIT100081 TSU100084')
#返回待匹配的文本
print(m.string)
#BIT100081 TSU100084
#返回匹配時使用的pattern對象(正則表達式)
print(m.re)
#re.compile('[1-9]\\d{5}')
#返回正則表達式搜索文本的開始位置
print(m.pos)
#0
#返回正則表達式搜索文本的結束位置
print(m.endpos)
#19
#返回獲得匹配後的字符串
print(m.group(0))
#10081
#返回匹配字符串在原始字符串的開始位置
print(m.start())
#3
#返回匹配字符串在原始字符串的結束位置
print(m.end())
#9
#返回返回(.start(),.end())
print(m.span())
#(3,9)
6.5 Re庫的貪婪匹配和最小匹配
- 貪婪匹配
Re庫默認採用貪婪匹配,即輸出匹配最長的子串。
import re
match = re.search(r'PY.*N','PYANBNCNDN')
print(match.group())
#PYANBNCNDN
- 如何輸出最短的子串呢?
match = re.search(r'PY.*?N','PYANBNCNDN')
print(match.group(0))
#'PYAN'
- 最小匹配操作符
操作符 | 說明 |
---|---|
*? | 前一個字符0次或無限次擴展,最小匹配 |
+? | 前一個字符1次或無限次擴展,最小匹配 |
?? | 前一個字符0次或1次擴展,最小匹配 |
{m,n}? | 擴展前一個字符m至n次(含n),最小匹配 |