正則表達式是一個特殊的字符序列,它能幫助你方便的檢查一個字符串是否與某種模式匹配。html
Python 自1.5版本起增長了re 模塊,它提供 Perl 風格的正則表達式模式。python
re 模塊使 Python 語言擁有所有的正則表達式功能。linux
compile 函數根據一個模式字符串和可選的標誌參數生成一個正則表達式對象。該對象擁有一系列方法用於正則表達式匹配和替換。正則表達式
re 模塊也提供了與這些方法,功能徹底一致的函數,這些函數使用一個模式字符串作爲它們的第一個參數。數據庫
本章節主要介紹 Python 中經常使用的正則表達式處理函數,若是你對正則表達式不瞭解,能夠查看咱們的 正則表達式 - 教程。express
split 方法按照可以匹配的子串將字符串分割後返回列表,它的使用形式以下:json
re.split(pattern, string[, maxsplit=0, flags=0])
參數:app
參數 | 描述 |
---|---|
pattern | 匹配的正則表達式 |
string | 要匹配的字符串。 |
maxsplit | 分隔次數,maxsplit=1 分隔一次,默認爲 0,不限制次數。 |
flags | 標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等。參見:正則表達式修飾符 - 可選標誌 |
import re # fLags=re.IGNORECASE:忽略大小寫 data = 'Last login: Tue Mar 31 17:56:11 2020 from 192.168.1.80' new_data = re.split('[:.]\s*', data) print(new_data) print(data.split(': '))
['Last login', 'Tue Mar 31 17', '56', '11 2020 from 192', '168', '1', '80'] ['Last login', 'Tue Mar 31 17:56:11 2020 from 192.168.1.80']
模式 | 描述 |
---|---|
^ | 匹配字符串的開頭 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了換行符,當re.DOTALL標記被指定時,則能夠匹配包括換行符的任意字符。 |
[...] | 用來表示一組字符,單獨列出:[amk] 匹配 'a','m'或'k' |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c以外的字符。 |
re* | 匹配0個或多個的表達式。 |
re+ | 匹配1個或多個的表達式。 |
re? | 匹配0個或1個由前面的正則表達式定義的片斷,非貪婪方式 |
re{ n} | 匹配n個前面表達式。例如,"o{2}"不能匹配"Bob"中的"o",可是能匹配"food"中的兩個o。 |
re{ n,} | 精確匹配n個前面表達式。例如,"o{2,}"不能匹配"Bob"中的"o",但能匹配"foooood"中的全部o。"o{1,}"等價於"o+"。"o{0,}"則等價於"o*"。 |
re{ n, m} | 匹配 n 到 m 次由前面的正則表達式定義的片斷,貪婪方式 |
實例 | 描述 |
---|---|
. | 匹配除 "\n" 以外的任何單個字符。要匹配包括 '\n' 在內的任何字符,請使用象 '[.\n]' 的模式。 |
\d | 匹配一個數字字符。等價於 [0-9]。 |
\D | 匹配一個非數字字符。等價於 [^0-9]。 |
\s | 匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價於 [^ \f\n\r\t\v]。 |
\w | 匹配包括下劃線的任何單詞字符。等價於'[A-Za-z0-9_]'。 |
\W | 匹配任何非單詞字符。等價於 '[^A-Za-z0-9_]'。 |
# ?[a-zA-Z]+ # ?用來匹配單詞先後可能出現的空格,[a-zA-Z]表明一個或多個英文字母 # 匹配一個IP地址 192.168.1.80 # [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
在字符串中找到正則表達式所匹配的全部子串,並返回一個列表,若是沒有找到匹配的,則返回空列表。echarts
注意: match 和 search 是匹配一次 findall 匹配全部。ide
語法格式爲:
re.findall(string[, pos[, endpos]])
參數:
import re pattern = re.compile(r'\d+') # 查找數字 result1 = pattern.findall('runoob 123 google 456') result2 = pattern.findall('run88oob123google456', 0, 10) print(result1) print(result2)
['123', '456'] ['88', '12']
compile 函數用於編譯正則表達式,生成一個正則表達式( Pattern )對象,供 match() 和 search() 這兩個函數使用。
語法格式爲:
re.compile(pattern[, flags])
參數:
re.I 忽略大小寫
>>>import re >>> pattern = re.compile(r'\d+') # 用於匹配至少一個數字 >>> m = pattern.match('one12twothree34four') # 查找頭部,沒有匹配 >>> print( m ) None >>> m = pattern.match('one12twothree34four', 2, 10) # 從'e'的位置開始匹配,沒有匹配 >>> print( m ) None >>> m = pattern.match('one12twothree34four', 3, 10) # 從'1'的位置開始匹配,正好匹配 >>> print( m ) # 返回一個 Match 對象 <_sre.SRE_Match object at 0x10a42aac0> >>> m.group(0) # 可省略 0 '12' >>> m.start(0) # 可省略 0 3 >>> m.end(0) # 可省略 0 5 >>> m.span(0) # 可省略 0 (3, 5)
在上面,當匹配成功時返回一個 Match 對象,其中:
group([group1, …])
方法用於得到一個或多個分組匹配的字符串,當要得到整個匹配的子串時,可直接使用 group()
或 group(0)
;start([group])
方法用於獲取分組匹配的子串在整個字符串中的起始位置(子串第一個字符的索引),參數默認值爲 0;end([group])
方法用於獲取分組匹配的子串在整個字符串中的結束位置(子串最後一個字符的索引+1),參數默認值爲 0;span([group])
方法返回 (start(group), end(group))
。import re # flags=re. IGNORECASE:忽略大小寫 data = 'Linux系統內置Python 2.7.5,咱們安裝了Python 3.8.1。' print(re.findall( 'python [0-9]\.[0-9]\.[0-9]', data, flags=re.IGNORECASE)) # re_obj = re.compile('python [0-9]\.[0-9]\.[0-9]', flags=re.IGNORECASE) print(re_obj.findall(data))
['Python 2.7.5', 'Python 3.8.1'] ['Python 2.7.5', 'Python 3.8.1']
[root@python ~]# seq 10000 > data.txt
import re def main(): pattern = "[0-9]+" with open('~/data.txt') as f: for line in f: re.findall(pattern, line) if __name__ == 'main': main()
import re def main() : pattern = "[0-9]+" re_obj = re.compile(pattern) with open("~/data.txt") as f: for line in f: re_obj.findall(line) if __name__ == "main": main( )
底部出現如下信息,上傳成功
[root@python ~]# cd /opt/ [root@python opt]# cd 練習 [root@python 練習]# ls 001.py findall.py compile.py
[root@python 練習]# time python3 findall.py real 0m0.058s user 0m0.005s sys 0m0.029s [root@python 練習]# time python3 compile.py real 0m0.018s user 0m0.014s sys 0m0.004s
經測試可看出compile讀取的方式更快
data = 'What is the difference between python 2.7.5 and Python 3.8.1 ?' import re print(re.findall('[0-9]\.[0-9]\.[0-9]',data)) print(re.findall('python [0-9]\.[0-9]\.[0-9]',data)) print(re.findall('Python [0-9]\.[0-9]\.[0-9]',data)) print(re.findall('ython [0-9]\.[0-9]\.[0-9]',data)) print(data.startswith('What')) print(data.endswith('?')) print(re.match('What',data)) word = "123 is one hender and twentyu-there" print(re.match('\d+',word)) r = re.match('\d+',word) print(r) print(r.start()) print(r.end()) print(r.re) print(r.group()) print(r.string) rr = re.finditer('[0-9]\.[0-9]\.[0-9]',data) print(rr) # print([r for r in rr]) for it in rr: print(it.group(0))
# 輸出'x.x.x'類型的數字 ['2.7.5', '3.8.1'] # 輸出'python x.x.x'類型的數字 ['python 2.7.5'] # 輸出'Python x.x.x'類型的數字 ['Python 3.8.1'] # 輸出'ython x.x.x'類型的數字 ['ython 2.7.5', 'ython 3.8.1'] # 查找data中是否有'What' True # 查找data中是否有'J' True # 查找data中是否有'What' <re.Match object; span=(0, 4), match='What'> # 查找data中是否有'數字字符' <re.Match object; span=(0, 3), match='123'> # 查找data中是否有'數字字符' <re.Match object; span=(0, 3), match='123'> # 匹配的子串在整個字符串中的起始位置 0 # 匹配的子串在整個字符串中的結束位置 3 # 獲取re函數的類型 re.compile('\\d+') # 得到一個或多個分組匹配的字符串 123 # 匹配的字符串 123 is one hender and twentyu-there # 輸出rr <callable_iterator object at 0x000001B92D1613D0> # 一行一行輸出rr文件的'x.x.x'類型的數字 2.7.5 3.8.1
re.match 嘗試從字符串的起始位置匹配一個模式,若是不是起始位置匹配成功的話,match()就返回none。
函數語法:
re.match(pattern, string, flags=0)
函數參數說明:
參數 | 描述 |
---|---|
pattern | 匹配的正則表達式 |
string | 要匹配的字符串。 |
flags | 標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等。參見:正則表達式修飾符 - 可選標誌 |
匹配成功re.match方法返回一個匹配的對象,不然返回None。
咱們可使用group(num) 或 groups() 匹配對象函數來獲取匹配表達式。
匹配對象方法 | 描述 |
---|---|
group(num=0) | 匹配的整個表達式的字符串,group() 能夠一次輸入多個組號,在這種狀況下它將返回一個包含那些組所對應值的元組。 |
groups() | 返回一個包含全部小組字符串的元組,從 1 到 所含的小組號。 |
import re print(re.match('www', 'www.runoob.com').span()) # 在起始位置匹配 print(re.match('com', 'www.runoob.com')) # 不在起始位置匹配
(0, 3) None
import re line = "Cats are smarter than dogs" # .* 表示任意匹配除換行符(\n、\r)以外的任何單個或多個字符 matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I) if matchObj: print ("matchObj.group() : ", matchObj.group()) print ("matchObj.group(1) : ", matchObj.group(1)) print ("matchObj.group(2) : ", matchObj.group(2)) else: print ("No match!!")
matchObj.group() : Cats are smarter than dogs matchObj.group(1) : Cats matchObj.group(2) : smarter
compile 函數用於編譯正則表達式,生成一個正則表達式( Pattern )對象,供 match() 和 search() 這兩個函數使用。
語法格式爲:
re.compile(pattern[, flags])
參數:
re.I 忽略大小寫
>>>import re >>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小寫 >>> m = pattern.match('Hello World Wide Web') >>> print( m ) # 匹配成功,返回一個 Match 對象 <_sre.SRE_Match object at 0x10bea83e8> >>> m.group(0) # 返回匹配成功的整個子串 'Hello World' >>> m.span(0) # 返回匹配成功的整個子串的索引 (0, 11) >>> m.group(1) # 返回第一個分組匹配成功的子串 'Hello' >>> m.span(1) # 返回第一個分組匹配成功的子串的索引 (0, 5) >>> m.group(2) # 返回第二個分組匹配成功的子串 'World' >>> m.span(2) # 返回第二個分組匹配成功的子串索引 (6, 11) >>> m.groups() # 等價於 (m.group(1), m.group(2), ...) ('Hello', 'World') >>> m.group(3) # 不存在第三個分組 Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: no such group
在上面,當匹配成功時返回一個 Match 對象,其中:
group([group1, …])
方法用於得到一個或多個分組匹配的字符串,當要得到整個匹配的子串時,可直接使用 group()
或 group(0)
;start([group])
方法用於獲取分組匹配的子串在整個字符串中的起始位置(子串第一個字符的索引),參數默認值爲 0;end([group])
方法用於獲取分組匹配的子串在整個字符串中的結束位置(子串最後一個字符的索引+1),參數默認值爲 0;span([group])
方法返回 (start(group), end(group))
。re.search 掃描整個字符串並返回第一個成功的匹配。
函數語法:
re.search(pattern, string, flags=0)
函數參數說明:
參數 | 描述 |
---|---|
pattern | 匹配的正則表達式 |
string | 要匹配的字符串。 |
flags | 標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等。參見:正則表達式修飾符 - 可選標誌 |
匹配成功re.search方法返回一個匹配的對象,不然返回None。
咱們可使用group(num) 或 groups() 匹配對象函數來獲取匹配表達式。
匹配對象方法 | 描述 |
---|---|
group(num=0) | 匹配的整個表達式的字符串,group() 能夠一次輸入多個組號,在這種狀況下它將返回一個包含那些組所對應值的元組。 |
groups() | 返回一個包含全部小組字符串的元組,從 1 到 所含的小組號。 |
import re print(re.search('www', 'www.runoob.com').span()) # 在起始位置匹配 print(re.search('com', 'www.runoob.com').span()) # 不在起始位置匹配
(0, 3) (11, 14)
re.match 只匹配字符串的開始,若是字符串開始不符合正則表達式,則匹配失敗,函數返回 None,而 re.search 匹配整個字符串,直到找到一個匹配。
import re line = "Cats are smarter than dogs" matchObj = re.match( r'dogs', line, re.M|re.I) if matchObj: print ("match --> matchObj.group() : ", matchObj.group()) else: print ("No match!!") matchObj = re.search( r'dogs', line, re.M|re.I) if matchObj: print ("search --> matchObj.group() : ", matchObj.group()) else: print ("No match!!")
No match!! search --> matchObj.group() : dogs
參數 | 描述 |
---|---|
pattern | 匹配的正則表達式 |
string | 要匹配的字符串。 |
flags | 標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等。參見:正則表達式修飾符 - 可選標誌 |
import re it = re.finditer(r"\d+","12a32bc43jf3") for match in it: print (match.group() )
12 32 43 3
Python 的re模塊提供了re.sub用於替換字符串中的匹配項。
語法:
re.sub(pattern, repl, string, count=0, flags=0)
參數:
前三個爲必選參數,後兩個爲可選參數。
import re phone = "2004-959-559 # 這是一個電話號碼" # 刪除註釋 num = re.sub(r'#.*$', "", phone) print ("電話號碼 : ", num) # 移除非數字的內容 num = re.sub(r'\D', "", phone) print ("電話號碼 : ", num)
電話號碼 : 2004-959-559 電話號碼 : 2004959559
如下實例中將字符串中的匹配的數字乘於 2:
import re # 將匹配的數字乘於 2 def double(matched): value = int(matched.group('value')) return str(value * 2) s = 'A23G4HFD567' print(re.sub('(?P<value>\d+)', double, s))
A46G8HFD1134
split 方法按照可以匹配的子串將字符串分割後返回列表,它的使用形式以下:
re.split(pattern, string[, maxsplit=0, flags=0])
參數 | 描述 |
---|---|
pattern | 匹配的正則表達式 |
string | 要匹配的字符串。 |
maxsplit | 分隔次數,maxsplit=1 分隔一次,默認爲 0,不限制次數。 |
flags | 標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等。參見:正則表達式修飾符 - 可選標誌 |
>>>import re >>> re.split('\W+', 'runoob, runoob, runoob.') ['runoob', 'runoob', 'runoob', ''] >>> re.split('(\W+)', ' runoob, runoob, runoob.') ['', ' ', 'runoob', ', ', 'runoob', ', ', 'runoob', '.', ''] >>> re.split('\W+', ' runoob, runoob, runoob.', 1) ['', 'runoob, runoob, runoob.'] >>> re.split('a*', 'hello world') # 對於一個找不到匹配的字符串而言,split 不會對其做出分割 ['hello world']
首先舉個例子:
example = "abbbbbbc" pattern = re.compile("ab+")
貪婪模式:正則表達式通常趨向於最大長度匹配,也就是所謂的貪婪匹配。如上面使用模式pattern 匹配字符串example,匹配到的結果就是」abbbbbb」整個字符串。
非貪婪模式:在整個表達式匹配成功的前提下,儘量少的匹配。如上面使用模式pattern 匹配字符串example,匹配到的結果就只是」ab」整個字符串。
在python中默認採用的是貪婪模式,使用非貪婪模式的話,只須要在量詞後面直接加上一個問號」?」。
在第一篇文章中介紹了正則表達式當中的量詞一共有五種:
在正則表達式中通常默認採用的是貪婪模式,在上面的例子當中已經匹配到了「ab」時已經可使整個表達式匹配成功,可是因爲採用的是貪婪模式,因此還須要日後繼續匹配,檢查時候存在更長的能夠匹配成功的字符串。一直到匹配到最後一個」b」的時候,後面已經沒有能夠成功匹配的字符串了,匹配結束。返回匹配結果「abbbbbb」。
因此,咱們能夠將貪婪模式理解爲:在整個表達式匹配成功的前提下,儘量多的匹配。
非貪婪模式也就是將咱們例子中的正則表達式「ab+」改成」ab+?」,當匹配到「ab」時,已經匹配成功,直接結束匹配,不在向後繼續嘗試,返回匹配成功的字符串」ab」。
因此,咱們能夠將非貪婪模式理解爲:在整個表達式匹配成功的前提下,儘量少的匹配
import re text = 'Beautifulis better than ugly. Explicit is better than implicit.' print(re.findall('Beautifulis.*\.',text)) print(re.findall('Beautifulis.*?\.',text))
['Beautifulis better than ugly. Explicit is better than implicit.'] ['Beautifulis better than ugly.']
貪婪與非貪婪模式影響的是被量詞修飾的子表達式的匹配行爲,貪婪模式在整個表達式匹配成功的前提下,儘量多的匹配;而非貪婪模式在整個表達式匹配成功的前提下,儘量少的匹配。
能達到一樣匹配結果的貪婪與非貪婪模式,一般是貪婪模式的匹配效率較高。 全部的非貪婪模式,均可以經過修改量詞修飾的子表達式,轉換爲貪婪模式。 貪婪模式能夠與固化分組結合,提高匹配效率,而非貪婪模式卻不能夠。
replace() 方法把字符串中的 old(舊字符串) 替換成 new(新字符串),若是指定第三個參數max,則替換不超過 max 次。
replace()方法語法:
str.replace(old, new[, max])
返回字符串中的 old(舊字符串) 替換成 new(新字符串)後生成的新字符串,若是指定第三個參數max,則替換不超過 max 次。
如下實例展現了replace()函數的使用方法:
data = 'What is the difference between python 2.7.5 and Python 3.8.1 ?' print(data) import re r_data = data.replace('2.7.5','x.x.x') r_data2 = r_data.replace('3.8.1','x.x.x') print(r_data2) print(re.sub('[0-9]\.[0-9]\.[0-9]','x.x.x',data)) print(data.split()) print(re.split('[ .]+',data))
What is the difference between python 2.7.5 and Python 3.8.1 ? What is the difference between python x.x.x and Python x.x.x ? What is the difference between python x.x.x and Python x.x.x ? ['What', 'is', 'the', 'difference', 'between', 'python', '2.7.5', 'and', 'Python', '3.8.1', '?'] ['What', 'is', 'the', 'difference', 'between', 'python', '2', '7', '5', 'and', 'Python', '3', '8', '1', '?']
from pyecharts.charts import Map from pyecharts import options as opt import requests import json #獲取數據 data = requests.get( 'https://gwpre.sina.cn/interface/fymap2020_data.json').content data = json.loads(data) print(data) #篩選數據 sub_data = list() for i in data['data']['list']: sub_data.append((i['name'],i['value'])) print(sub_data) #繪製中國地圖 map_info = Map() #設置地圖的基本信息 map_info.set_global_opts(title_opts=opt.TitleOpts('實時疫情地圖——'+data['data' ]['times'] ,subtitle='數據來源', subtitle_link='https://news.sina.cn/zt_d/yiqing0121?vt=4&pos=222') ,visualmap_opts=opt.VisualMapOpts (max_=1500,is_piecewise=True)) map_info.add('確診', sub_data, maptype='china') #生成網頁文件 map_info.render( '20200403.html' )
import re import requests r = requests.get('https://www.lagou.com/beijing') # print(r) result = re.findall('"(https?://.*?)"',r.content.decode('utf-8')) print(result)
['https://www.lagou.com/beijing/', 'https://www.lagou.com/', 'https://www.lagou.com/about.html', 'http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802024043', 'https://www.lagou.com/upload/oss.js?v=1010'] -----