正则表达式介绍+一些简单应用
一、正則語句介紹
| 語法 | 說明 | 表達式示例 | 完整匹配的字符串 |
| 一般字符 | 匹配自身 | abc | abc |
| . | 除換行符'\n'以外的任意字符 | a.c | abc |
| \ | 轉義字符,是后一個字符改變原來的意思 | a\.c | a.c |
| [...] | 字符集,所有的特殊字符在字符集中都失去其原有的特殊含義 | a[bcd]e | abe? ace? ade |
| \d | 數字[0-9] | a\dc | a1c |
| \D | 非數字[^\d] | a\Dc | abc |
| \s | 空白符 [<空格>\t\r\n\f\v] | a\sc | a c |
| \S? | 非空白字符[^\s] | a\Sc | abc |
| \w | 單詞字符[A-Za-z0-9_] | a\wc | abc |
| \W | 非單詞字符 [^\W] | a\Wc | a c |
| * | 匹配前一個字符0或無限次 | abc* | ab? ?abcccccc |
| + | 匹配前一個字符1次或無限次 | abc+ | abc abccccc |
| ? | 匹配前一個字符0或1次 | abc? | ab abc |
| {m} | 匹配前一個字符m次 | ab{2}c | abbc |
| {m,n} | 匹配前一個字符m到n次 | ab{1,2}c | abc? abbc |
| ^ | 開頭 | ^abc | abc |
| $ | 末尾 | abc$ | abc |
| \A | 僅匹配字符串開頭 | ||
| \Z | 僅匹配字符串末尾 | ||
| \b | 匹配單詞和非單詞之間 | a\b!bc | a!bc |
| \B | [^\b] | a\Bbc | abc |
| | | 左右表達式任意匹配一個(先嘗試左邊) | abc|def | abc def |
| (...) | 分組表達式 | (abc){2} | abcabc |
| (?P=name) | 分組,除了原有的編號外在指定一個額外的別名 | ||
| \<number> | 引用編號為<number>的分組匹配到的字符串 | ||
| (?P=name) | 引用別名為<name>的分組匹配到的字符串 |
1、貪婪模式
正則表達式通常用于在文本中查找匹配的字符串。Python里數量詞默認是貪婪的,總是嘗試匹配盡可能多的字符;非貪婪的則相反,總是嘗試匹配盡可能少的字符。例如:正則表達式"ab"如果用于查找"abbbc",將找到"abbb"。而如果使用非貪婪的數量詞"ab?",將找到"a"。
2. 反斜杠的困擾
正則表達式里使用"\"作為轉義字符,這就可能造成反斜杠困擾。假如你需要匹配文本中的字符"\",那么使用編程語言表示的正則表達式里將需要4個反斜杠"\\\\":前兩個和后兩個分別用于在編程語言里轉義成反斜杠,轉換成兩個反斜杠后再在正則表達式里轉義成一個反斜杠。
3. 匹配模式
正則表達式提供了一些可用的匹配模式,比如忽略大小寫、多行匹配等
二、re模塊簡介
聊到Python正則表達式的支持,首先肯定會想到re庫,這是一個Python處理文本的標準庫。
標準庫的意思表示這是一個Python內置模塊,不需要額外下載,目前Python內置模塊大概有300個。可以在這里查看Python所有的內置模塊:Python Module Index — Python 3.10.3 documentation
因為re是內置模塊,所以不需要再下載,使用時直接引入即可:? ?import re
re模塊官方文檔:re --- 正則表達式操作 — Python 3.8.13 文檔
re模塊庫源碼:https://github.com/python/cpython/blob/3.8/Lib/re.p
三、re模塊常量
常量即表示不可更改的變量,一般用于做標記。
re模塊中有9個常量,常量的值都是int類型!
1. IGNORECASE
語法: re.IGNORECASE 或簡寫為 re.I
作用: 進行忽略大小寫匹配。
代碼案例:
text = '這是一個例子b' pattern = r'這是一個例子B' print('默認模式', re.findall(pattern, text)) print('忽略大小寫', re.findall(pattern, text, re.I))默認模式:[] 忽略大小寫:['這是一個例子B']在默認匹配模式下大寫字母B無法匹配小寫字母b,而在 忽略大小寫 模式下是可以的。
2. ASCII
語法: re.ASCII 或簡寫為 re.A
作用: 顧名思義,ASCII表示ASCII碼的意思,讓 \w, \W, \b, \B, \d, \D, \s 和 \S 只匹配ASCII,而不是Unicode。
代碼案例:
text = '這是a一個例子b' pattern = r'\w+' print('Unicode', re.findall(pattern, text)) print('ASCII', re.findall(pattern, text, re.A))Unicode:['這是a一個例子b'] ASCII:['a','b']在默認匹配模式下\w+匹配到了所有字符串,而在ASCII模式下,只匹配到了a、b、c(ASCII編碼支持的字符)。
注意:這只對字符串匹配模式有效,對字節匹配模式無效。
3. DOTALL
語法: re.DOTALL 或簡寫為 re.S
作用: DOT表示.,ALL表示所有,連起來就是.匹配所有,包括換行符\n。默認模式下.是不能匹配行符\n的。
代碼案例:
text = '這是一個\n例子' pattern = r'.*' print('默認模式', re.findall(pattern, text)) print('匹配所有模式', re.findall(pattern, text, re.S))默認模式:['這是一個', '', '例子', ''] 匹配所有模式:['這是一個\n例子', '']在默認匹配模式下.并沒有匹配換行符\n,而是將字符串分開匹配;而在re.DOTALL模式下,換行符\n與字符串一起被匹配到。
注意:默認匹配模式下.并不會匹配換行符\n。
4. MULTILINE
語法: re.MULTILINE 或簡寫為 re.M
作用: 多行模式,當某字符串中有換行符\n,默認模式下是不支持換行符特性的,比如:行開頭 和 行結尾,而多行模式下是支持匹配行開頭的。
代碼案例:
text = '這是\n一個例子' pattern = r'^一個例子' print('默認模式', re.findall(pattern, text)) print('多行', re.findall(pattern, text, re.M))默認模式:[] 多行:['一個例子']正則表達式中^表示匹配行的開頭,默認模式下它只能匹配字符串的開頭;而在多行模式下,它還可以匹配 換行符\n后面的字符。
注意:正則語法中^匹配行開頭、\A匹配字符串開頭,單行模式下它兩效果一致,多行模式下\A不能識別\n。
四、re模塊函數
re模塊有12個函數,重點介紹常用模塊。
1.查找一個匹配項
查找并返回一個匹配項的函數有3個:search、match、fullmatch,他們的區別分別是:
search: 查找任意位置的匹配項
match: 必須從字符串開頭匹配
fullmatch: 整個字符串與正則完全匹配
我們再來根據實際的代碼案例比較:
案例1:
import re text = 'a這是一個例子b,這是一個例子b' pattern = r'這是一個例子b'print('search:', re.search(pattern, text).group()) print('match:', re.match(pattern, text)) print('fullmatch: ', re.fullmatch(pattern,text))search:這是一個例子b match:None fullmatch:None案例1中search函數是在字符串中任意位置匹配,只要有符合正則表達式的字符串就匹配成功,其實有兩個匹配項,但search函數值返回一個。
而match函數是要從頭開始匹配,而字符串開頭多了個字母a,所以無法匹配,fullmatch函數需要完全相同,故也不匹配!
2.查找多個匹配項
講完查找一項,現在來看看查找多項吧,查找多項函數主要有:findall函數 與 finditer函數:
findall: 從字符串任意位置查找,返回一個列表
finditer:從字符串任意位置查找,返回一個迭代器
兩個方法基本類似,只不過一個是返回列表,一個是返回迭代器。我們知道列表是一次性生成在內存中,而迭代器是需要使用時一點一點生成出來的,內存使用更優。
import re text = 'a這是一個例子b,這是一個例子b' pattern = r'這是一個例子b' print('findall:', re.findall(pattern, text)) print('finditer:', list(re.finditer(pattern, text)))findall: ['這是一個例子b', '這是一個例子b'] finditer: [<_sre.SRE_Match object; span=(1, 8), match='這是一個例子b'>, <_sre.SRE_Match object; span=(9, 16), match='這是一個例子b'>]如果可能存在大量的匹配項的話,建議使用finditer函數,一般情況使用findall函數基本沒啥影響。
3.分割
re.split(pattern, string, maxsplit=0, flags=0) 函數:用 pattern 分開 string , maxsplit表示最多進行分割次數, flags表示模式,就是上面我們講解的常量!
import re text = 'a這是一個例子b,這是一個例子b' pattern = r',' print('split: ', re.split(pattern,text,maxsplit=1,flags=re.I))split: ['a這是一個例子b', '這是一個例子b']注意:str模塊也有一個 split函數 ,那這兩個函數該怎么選呢? str.split函數功能簡單,不支持正則分割,而re.split支持正則。
關于二者的速度如何? 在 不需要正則支持 且 數據量和數次不多 的情況下使用str.split函數更合適,反之則使用re.split函數。
4.替換
替換主要有sub函數 與 subn函數,他們功能類似!
先來看看sub函數的用法:
re.sub(pattern, repl, string, count=0, flags=0) 函數參數講解:repl替換掉string中被pattern匹配的字符, count表示最大替換次數,flags表示正則表達式的常量。
值得注意的是:sub函數中的入參:repl替換內容既可以是字符串,也可以是一個函數哦! 如果repl為函數時,只能有一個入參:Match匹配對象。
re.subn(pattern, repl, string, count=0, flags=0) 函數與 re.sub函數 功能一致,只不過返回一個元組 (字符串, 替換次數)。
5.編譯正則對象
compile函數 與 template函數 將正則表達式的樣式編譯為一個 正則表達式對象 (正則對象Pattern),這個對象與re模塊有同樣的正則函數(后面我們會講解Pattern正則對象)。
import re text = 'a這是一個例子b,這是一個例子b' pattern = r'這是一個例子b' pattern_obj = re.compile(pattern) # 查找任意位置 print('search:', pattern_obj.search(text).group())search: 這是一個例子b而template函數 與 compile函數 類似,只不過是增加了我們之前說的re.TEMPLATE 模式
五、正則對象Pattern
1. 與re模塊 函數一致
.在re模塊的函數中有一個重要的函數 compile函數 ,這個函數可以預編譯返回一個正則對象,此正則對象擁有與re模塊相同的函數.
既然是一致的,那到底該用re模塊 還是 正則對象Pattern ?
而且,有些同學可能看過re模塊的源碼,你會發現其實compile函數 與 其他 re函數(search、split、sub等等) 內部調用的是同一個函數,最終還是調用正則對象的函數!
就是以下兩種代碼的底層實現是一致的:
# re函數
re.search(pattern, text)
# 正則對象函數
compile = re.compile(pattern)
compile.search(text)
官方文檔推薦:在多次使用某個正則表達式時推薦使用正則對象Pattern 以增加復用性,因為通過 re.compile(pattern) 編譯后的模塊級函數會被緩存!
六、注意事項
1.字節串 與 字符串
模式和被搜索的字符串既可以是Unicode字符串(str),也可以是8位字節串(bytes)。但是,兩者不能混用!
2.r 的作用
正則表達式使用反斜杠('')來表示特殊形式,或者把特殊字符轉義成普通字符。
而反斜杠在普通的 Python 字符串里也有相同的作用,所以就產生了沖突。
解決辦法是對于正則表達式樣式使用 Python 的原始字符串表示法;在帶有 'r' 前綴的字符串字面值中,反斜杠不必做任何特殊處理。
3.正則查找函數 返回匹配對象
查找一個匹配項(search、match、fullmatch)的函數返回值都是一個匹配對象Match,需要通過match.group()獲取匹配值。
match.group()和match.groups()也是有區別的。
4.重復使用某個正則
如果要重復使用某個正則表達式,推薦使用re.compile(pattern)函數返回一個正則對象。
七、re.compile、re.match及re.search函數用法詳解
參考? ?https://www.jb51.net/article/141830.htm
1、re.compile() 函數
編譯正則表達式模式,返回一個對象。可以把常用的正則表達式編譯成正則表達式對象,方便后續調用及提高效率。
re.compile(pattern, flags=0)
- pattern 指定編譯時的表達式字符串
- flags 編譯標志位,用來修改正則表達式的匹配方式。支持 re.L|re.M 同時匹配
flags 標志位參數
re.I(re.IGNORECASE)
使匹配對大小寫不敏感
re.L(re.LOCAL)?
做本地化識別(locale-aware)匹配
re.M(re.MULTILINE)?
多行匹配,影響 ^ 和 $
re.S(re.DOTALL)
使 . 匹配包括換行在內的所有字符
re.U(re.UNICODE)
根據Unicode字符集解析字符。這個標志影響 \w, \W, \b, \B.
re.X(re.VERBOSE)
該標志通過給予你更靈活的格式以便你將正則表達式寫得更易于理解。
示例:
| 1 2 3 4 5 6 7 | import re content = 'Citizen wang , always fall in love with neighbour,WANG' rr = re.compile(r'wan\w', re.I) # 不區分大小寫 print(type(rr)) a = rr.findall(content) print(type(a)) print(a) |
findall 返回的是一個 list 對象
<class '_sre.SRE_Pattern'>
<class 'list'>
['wang', 'WANG']
2、re.match() 函數
總是從字符串‘開頭曲匹配',并返回匹配的字符串的 match 對象?<class '_sre.SRE_Match'>。
re.match(pattern, string[, flags=0])
- pattern 匹配模式,由 re.compile 獲得
- string 需要匹配的字符串
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import re pattern = re.compile(r'hello') a = re.match(pattern, 'hello world') b = re.match(pattern, 'world hello') c = re.match(pattern, 'hell') d = re.match(pattern, 'hello ') if a: ??print(a.group()) else: ??print('a 失敗') if b: ??print(b.group()) else: ??print('b 失敗') if c: ??print(c.group()) else: ??print('c 失敗') if d: ??print(d.group()) else: ??print('d 失敗') |
hello
b 失敗
c 失敗
hello
match 的方法和屬性
參考鏈接
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import re str = 'hello world! hello python' pattern = re.compile(r'(?P<first>hell\w)(?P<symbol>\s)(?P<last>.*ld!)') # 分組,0 組是整個 hello world!, 1組 hello,2組 ld! match = re.match(pattern, str) print('group 0:', match.group(0)) # 匹配 0 組,整個字符串 print('group 1:', match.group(1)) # 匹配第一組,hello print('group 2:', match.group(2)) # 匹配第二組,空格 print('group 3:', match.group(3)) # 匹配第三組,ld! print('groups:', match.groups())? # groups 方法,返回一個包含所有分組匹配的元組 print('start 0:', match.start(0), 'end 0:', match.end(0)) # 整個匹配開始和結束的索引值 print('start 1:', match.start(1), 'end 1:', match.end(1)) # 第一組開始和結束的索引值 print('start 2:', match.start(1), 'end 2:', match.end(2)) # 第二組開始和結束的索引值 print('pos 開始于:', match.pos) print('endpos 結束于:', match.endpos) # string 的長度 print('lastgroup 最后一個被捕獲的分組的名字:', match.lastgroup) print('lastindex 最后一個分組在文本中的索引:', match.lastindex) print('string 匹配時候使用的文本:', match.string) print('re 匹配時候使用的 Pattern 對象:', match.re) print('span 返回分組匹配的 index (start(group),end(group)):', match.span(2)) |
返回結果:
group 0: hello world!
group 1: hello
group 2:?
group 3: world!
groups: ('hello', ' ', 'world!')
start 0: 0 end 0: 12
start 1: 0 end 1: 5
start 2: 0 end 2: 6
pos 開始于: 0
endpos 結束于: 25
lastgroup 最后一個被捕獲的分組的名字: last
lastindex 最后一個分組在文本中的索引: 3
string 匹配時候使用的文本: hello world! hello python
re 匹配時候使用的 Pattern 對象: re.compile('(?P<first>hell\\w)(?P<symbol>\\s)(?P<last>.*ld!)')
span 返回分組匹配的 index (start(group),end(group)): (5, 6)?
3、re.search 函數
對整個字符串進行搜索匹配,返回第一個匹配的字符串的 match 對象。
re.search(pattern, string[, flags=0])
- pattern 匹配模式,由 re.compile 獲得
- string 需要匹配的字符串
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import re str = 'say hello world! hello python' pattern = re.compile(r'(?P<first>hell\w)(?P<symbol>\s)(?P<last>.*ld!)') # 分組,0 組是整個 hello world!, 1組 hello,2組 ld! search = re.search(pattern, str) print('group 0:', search.group(0)) # 匹配 0 組,整個字符串 print('group 1:', search.group(1)) # 匹配第一組,hello print('group 2:', search.group(2)) # 匹配第二組,空格 print('group 3:', search.group(3)) # 匹配第三組,ld! print('groups:', search.groups())? # groups 方法,返回一個包含所有分組匹配的元組 print('start 0:', search.start(0), 'end 0:', search.end(0)) # 整個匹配開始和結束的索引值 print('start 1:', search.start(1), 'end 1:', search.end(1)) # 第一組開始和結束的索引值 print('start 2:', search.start(1), 'end 2:', search.end(2)) # 第二組開始和結束的索引值 print('pos 開始于:', search.pos) print('endpos 結束于:', search.endpos) # string 的長度 print('lastgroup 最后一個被捕獲的分組的名字:', search.lastgroup) print('lastindex 最后一個分組在文本中的索引:', search.lastindex) print('string 匹配時候使用的文本:', search.string) print('re 匹配時候使用的 Pattern 對象:', search.re) print('span 返回分組匹配的 index (start(group),end(group)):', search.span(2)) |
注意 re.search 和 re.match 匹配的 str 的區別
打印結果:
group 0: hello world!
group 1: hello
group 2:?
group 3: world!
groups: ('hello', ' ', 'world!')
start 0: 4 end 0: 16
start 1: 4 end 1: 9
start 2: 4 end 2: 10
pos 開始于: 0
endpos 結束于: 29
lastgroup 最后一個被捕獲的分組的名字: last
lastindex 最后一個分組在文本中的索引: 3
string 匹配時候使用的文本: say hello world! hello python
re 匹配時候使用的 Pattern 對象: re.compile('(?P<first>hell\\w)(?P<symbol>\\s)(?P<last>.*ld!)')
span 返回分組匹配的 index (start(group),end(group)): (9, 10)
八、一些簡單應用
1、識別網頁文本信息中的公網安 備案號
示例:滬公網備標識31011202007523
? ? ? ? ? ?閩公網安備35020302000108號
? ? ? ? ? ?京公網安備11010502026042
分析:【前邊一個字是每個省的簡稱】+【公網安備,還可能有 標識】+【數字特征】+【可能有 號】
import re pattern = re.compile("[京津晉冀蒙遼吉黑滬蘇浙皖閩贛魯豫鄂湘粵桂瓊渝川貴云藏陜甘青寧新]公網安['標識','備','證']\s*\d{10,15}號?") number = pattern.findall(col)2、匹配某兩個字符之間的信息
示例:提取gene_name信息:
| Gene_id=XLOC_003495;Gene_name=linc-DTHD1-11;Tr... |
3、匹配電話號碼
import re phone = "2004-959-559 # 這是一個電話號碼" # 刪除注釋 num = re.sub(r'#.*$', "", phone) print ("電話號碼 : ", num) # 電話號碼 : 2004-959-559 # 移除非數字的內容 num = re.sub(r'\D', "", phone) print ("電話號碼 : ", num)參考文獻:https://segmentfault.com/a/1190000022242427
總結
以上是生活随笔為你收集整理的正则表达式介绍+一些简单应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux下drcom无法上网,安装dr
- 下一篇: 倒桩 笔记