python3.7正则表达式语法_python3正则表达式的几个高级用法
python3正則表達式的幾個高級用法
一、 概述
本文舉例說明python3正則表達式的一些高級級法,主要是各類分組,可應用于
1、復雜網頁文件中的有用數據
例如,采用爬蟲技術取得網頁后,對網頁內任何數據進行提取分析
2、 各類配置文件
可能是屬性文件,讀取屬性文件中的鍵值對
可能是數據庫各類查詢的復雜匹配的參數解析,類似mybatis的動態sql語句解析,hibernate動態參數sql分析
二、 理解正則表達式的貪婪與非貪婪
1、 生活中的貪婪與非貪婪
例如公司員工餐廳發小西紅柿,每人一次可以領取1—10個
如果有的人每次都領取10個,則這個人屬于貪婪,就是在不犯錯時,每次取最多
如果有的人每次都領取1個,則這個人屬于不貪婪,就是在不犯錯時,每次取最少
2、 正則表達式的貪婪與非貪婪定義
只有前面的字符串內容可多可少時,才存在貪婪與非貪婪
1) 貪婪語法
.*,取盡可能多的任意字符
\w+,取盡可能多的任意英文字母與數字一次以上
\d{2,5},盡可能取到2--5個數字字母
\s+,},盡可能取到任意多個空格一次以上
.?,任意字符取0次,或1次,盡可能取1次2) 非貪婪語法
就是在貪婪定義后面加一個?
.*?,取盡可能少的任意字符,盡可能不取
\w+?,取盡可能少的任意英文字母與數字,盡可能只取1個
\d{2,5},盡可能少數字字母,盡可能只取2個
\s+,},盡可能取到最少空格,盡可能只取1個空格
.??,任意字符取0次,或1次,盡可能取0次
3) 貪婪與貪婪的最終匹配
無論貪婪,還是非貪婪,都要與后面內容繼續匹配,才能最終確定本次匹配內容,有時給合后面匹配內容時,兩都取值相同
3、 示例分析如下
python語法如下
import re
匹配到的結果列表=re.findall(r’正則字符串’,要匹配的字符串,re.I|re.S)
re.I,表示忽略大小寫
re.S,表示忽略回行,所有字符包括回行字符
字符串貪婪正則非貪婪正則www.baidu.com/num正則:www\.baidu\.com\/.*則能匹配到www.baidu.com/num有num正則www\.baidu\.com\/.*?則能匹配到www.baidu.com/無num
www.baidu.com/num/456www\.baidu\.com\/.*\/\d+則能匹配到www.baidu.com/num/456www\.baidu\.com\/.*?\/\d+則能匹配到www.baidu.com/num/456此時與貪婪正則匹配相同
一段網頁文本,希望能求出每個div的innerHTML
…. …. …. …. 正則 .* 則不能匹配出每個 標簽之間的文本innerText正則.*?則能匹配出每個標簽之間的文本innerText4、示例代碼如下import re
s1=re.findall(r'\D+\d+','abc123456') #結果為:['abc123456']
s2=re.findall(r'\D+\d+?','abc123456') #結果為:['abc1']
s2=re.findall(r'\D+\d*','abc123456') #結果為:['abc123456']
s2=re.findall(r'\D+\d*?','abc123456') #結果為:['abc']
s2=re.findall(r'\D+\d{2,4}','abc123456') #結果為:['abc1234']
s2=re.findall(r'\D+\d{2,4}?','abc123456',re.I) #結果為:['abc12']
s2=re.findall(r'\D+\d?','abc123456',re.I) #結果為:['abc1']
s2=re.findall(r'\D+\d??','abc123456',re.I) #結果為:['abc']
三、 正則表達式的自定義命名分組,(?P)
1、 語法說明
一個正則表達式可以有多個自定義名稱的分組,可以能過分組名稱提取到匹配的字符串
每一個分組定義是(?P<自定義分組名稱>正則字符串)
例如
pattern=r’正則1(?P<組1>組1正則)正則2(?P<組2>組2正則)正則3(?P<組3>組3正則)’
2、 需求如下
這是一段java代碼字符串,有下面幾種分析需求
1) 需求1,求3個參數,,,,3組實現
a) 每個變量的數據類型
類型名稱前后有數量不相同的空格
b) 每個變量名稱
變量名稱前有數量不相同的空格,后面有等號,等號前后有數量不相同的空格
c) 每個變量的值
值的前后有數量不相同的空格
變量最后一定有分號
2) 需求2,求2個參數, ,,2組實現
a) 每個變量名稱
要清除變量前后空格
b) 每個變量的值
要清除值前后空格
3) 需求3,求1個參數,,1組實現
每個變量的值
要清除值前后空格
4) 需求4,求1個參數,,1組實現
每個變量名稱
要清除變量名稱前后空格
3、 示例代碼str='''
String s1="學習java";
String s2= " ";
Float 價格=24000.89;
String desc = "用于找工作技能提升。。。" ;
Integer num = 12567 ;
'''
import re
#需求1,,分3組:,,,求數據類型,變量名稱,變量的值,下面3種求法,結果相同
s1=re.findall(r'(?=String|Float|Integer)(?P\w+)\s+(?P.*?)\s*?=\s*?(?P.*?)\s*?;',str,re.I|re.S); #結果是:[('String', 's1', '"學習java"'), ('String', 's2', ' " "'), ('Float', '價格', '24000.89'), ('String', 'desc', ' "用于找工作技能提升。。。"'), ('Integer', 'num', ' 12567')]
s1=re.findall(r'(?PString|Float|Integer\s+?\w+)\s+(?P.*?)\s*?=\s*?(?P["\d].*?)\s*?;',str,re.I|re.S); #結果是:[('String', 's1', '"學習java"'), ('String', 's2', ' " "'), ('Float', '價格', '24000.89'), ('String', 'desc', ' "用于找工作技能提升。。。"'), ('Integer', 'num', ' 12567')]
#優化上面,當變量前面有空格時,要清除["\d],表示雙引號或數字開頭,匹配結果自動加入到組,正則語法為:不消耗前綴
s1=re.findall(r'(?=String|Float|Integer)(?P\w+)\s+(?P.*?)\s*?=\s*?(?=["\d])(?P.*?)\s*?;',str,re.I|re.S); #結果是:[('String', 's1', '"學習java"'), ('String', 's2', '" "'), ('Float', '價格', '24000.89'), ('String', 'desc', '"用于找工作技能提升。。。"'), ('Integer', 'num', '12567')]
#需求2,分2組:,,求變量名稱,變量的值,
s1=re.findall(r'\s+?(?P\S+?)\s*?=\s*?(?P["\d].*?)\s*?;',str,re.I|re.S); #結果是:[('s1', '"學習java"'), ('s2', '" "'), ('價格', '24000.89'), ('desc', '"用于找工作技能提升。。。"'), ('num', '12567')]
#需求3,分1組,求每個變量的值,要清除首尾空格,給出2種求法
s1=re.findall( r'=\s*?(?P[\d"].*?)\s*?;',str,re.I|re.S); #結果是:['"學習java"', '" "', '24000.89', '"用于找工作技能提升。。。"', '12567']
s1=re.findall( r'=\s*?(?=[\d"])(?P.*?)\s*?;',str,re.I|re.S); #結果是:['"學習java"', '" "', '24000.89', '"用于找工作技能提升。。。"', '12567']
#需求4,分1個只取變量名稱
s1=re.findall(r'.*?\s+(?P\w+?)\s*?=.*?;',str,re.I|re.S); #結果是:['s1', 's2', '價格', 'desc', 'num']
四、 應用擴展
可以采用類似的方法,對任意復雜業務的sql語句進行配置分析,可能有任意多個字段條件操作,每個字段的值可能有或無,或在某一個范圍,這樣結合前臺提交,后臺用正則分組,可以提取任意復雜的sql條件查詢,適用于hibernate的動態查詢,及springjdbc自定義sql
1、 實現需求
當一個分組內容,重復出現2次或以上時,第2次起,可以引用前面定義的分組匹配,即
r’(P?pattern1)…(P?pattern2)…(P?pattern2)…(?P=name1)…(P=name2)…(?P=name3)’
即(?P=name1)重復匹配前面定義的(?Ppattern1),
(?P=name2)重復匹配前面定義的(?Ppattern2)
2、 示例如下import re
#假設下面的每門課的學費,例如oracle:500元,java:1550元
str='''
oracle:500,
java:1550,
bigdata:2000,
php:500
500
1550
2000
500
'''
#下面2行代碼結果相同
s1=re.findall(r'oracle:(?P\d+),.*?java:(?P\d+),.*?bigdata:(?P\d+),.*?php:(?P\d+).*?(?P=name1).*?(?P=name2).*?(?P=name3).*?(?P=name4).*?',str,re.I|re.S) #結果是:['500', '1800', '2000', '555']
s1=re.findall(r'oracle:(?P\d+),.*?java:(?P\d+),.*?bigdata:(?P\d+),.*?(?P=name1).*?(?P=name2).*?',str,re.I|re.S) #結果是:['500', '1800', '2000', '555']
五、 數字分組,\number
1、 語法說明
每一段正則用一個加圓括起來時,便自動構成一個組,包括(?Ppattern)自定義命名組,也加入到分組序號中
如果后面有前面圓括中相同部分,則用數字序號表示匹配相同部分
r’(正則1)…(正則2)…(正則3) 。。。\1….\2….\3…’,
這里出現\1,表示匹配前面第1個圓括號正則內容,
這里出現\2,表示匹配前面第2個圓括號正則內容
2、 可以用數組分組取得自定義命名分組
例如用:\2 取得前面第2個圓括號(?Ppattern123)的內容
3、 示例如下import re
#假設下面的每門課的學費,例如oracle:500元,java:1550元,bigdata:2000元,php:500元
str='''
oracle:500,
java:1550,
bigdata:2000,
php:500
500
1550
2000
500
'''
#下面需求求所有每門課的學費,只求具體數字,體會(?P)用法,下面2行代碼結果相同
s1=re.findall(r'\D+:(?P\d+),??',str,re.I|re.S) #結果是:['500', '1550', '2000', '500']
s1=re.findall(r'(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
#下面需求,求出課程名稱,及費用,4門課
s1=re.findall(r'.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
#下面3行代碼結果相同,括號的序號從1開始,(?P...)也算一個括號
s1=re.findall(r'(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?<\1>(?P=name1)\1>.*?<\3>(?P=name2)\3>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550')]
s1=re.findall(r'(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?<\1>\2\1>.*?<\3>(?P=name2)\3>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550')]
s1=re.findall(r'(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?<\1>\2\1>.*?<\3>\4\3>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550')]
#下面2行結果相同
s1=re.findall(r'.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?<\1>\2\1>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
s1=re.findall(r'.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?<\1>(?P=name1)\1>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
#下面2行結果相同
s1=re.findall(r'.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?<\1>(?P=name1)\1>.*?<\3>\4\3>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
s1=re.findall(r'.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?<\1>(?P=name1)\1>.*?<\3>(?P=name2)\3>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
#下面2行結果相同
s1=re.findall(r'.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?<\1>(?P=name1)\1>.*?<\3>(?P=name2)\3>.*?<\5>\6\5>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
s1=re.findall(r'.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?<\1>(?P=name1)\1>.*?<\3>(?P=name2)\3>.*?<\5>(?P=name3)\5>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
#下面2行結果相同
s1=re.findall(r'.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?<\1>(?P=name1)\1>.*?<\3>(?P=name2)\3>.*?<\5>\6\5>.*?<\7>\8\77>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
s1=re.findall(r'.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+),.*?(\w+):(?P\d+).*?<\1>(?P=name1)\1>.*?<\3>(?P=name2)\3>.*?<\5>\6\5>.*?<\7>(?P=name4)\7>.*?',str,re.I|re.S) #結果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]
s1=re.findall(r'(\D+):(?P\d+),.*?(\D+):(?P\d+),.*?(\D+):(?P\d+),.*?(\D+):(?P\d+),.*?<\1>(?P=name1)<\1>.*?',str,re.I|re.S) #結果是:['500', '1800', '2000', '555']
#下面
s1=re.findall(r'oracle:(?P\d+),.*?java:(?P\d+),.*?bigdata:(?P\d+),.*?php:(?P\d+).*?(?P=name1).*?(?P=name2).*?(?P=name3).*?(?P=name4).*?',str,re.I|re.S) #結果是:['500', '1800', '2000', '555']
s1=re.findall(r'oracle:(?P\d+),.*?java:(?P\d+),.*?bigdata:(?P\d+),.*?(?P=name1).*?(?P=name2).*?',str,re.I|re.S) #結果是:['500', '1800', '2000', '555']
六、 前置肯定分組,(?=pattern)
1、 實現需求
表示以。。。開頭,不消耗匹配內容,而是加入后面正則表達式中,所以也稱為前置不消耗分組
r’…(?=pattern1)(?Ppattern123)…’等效于
r’… (?Ppattern1pattern123)…’
2、 示例如下#前置肯定(?=pattern)
import re
#查詢url是否以http://www.開頭
s1=re.findall(r'(?=http:\/\/www\.)(?P.*)','http://www.baidu.com') #結果是:['http://www.baidu.com']
s1=re.findall(r'(?=http:\/\/www\.)(?P.*)','https://www.baidu.com') #結果是:[]
七、 前置否定分組,(?!pattern)
1、 實現需求
表示不包含。。。開頭的其余部分,
r’…(!pattern1)(?Ppattern123)…’等效于
r’… (?P!pattern1pattern123)…’,pattern1的內容只是一個最小正則內容
2、 示例如下#前置否定(?!pattern)
import re
#查詢url不包含http://開頭以外的其余部分
s1=re.findall(r'(?!http:\/\/)(?Pwww.*)','http://www.baidu.com') #結果是:['www.baidu.com']
#查詢所有非數字部分,即前面不包含數字,后面是字母
s1=re.findall(r'(?!\d+)(?P\D+)','123java456oracle367bigdata478') #結果是:['java', 'oracle', 'bigdata']
八、 后置肯定分組,(?<=pattern)
1、 實現需求
表示包含以。。。結尾的所有部分,不消耗匹配內容,而是加入前面分組中
r’… (?Ppattern123)(?<=pattern1)…’等效于
r’… (?Ppattern123pattern1)…’
2、 示例如下#后置肯定(?<=pattern)
#下面匹配前面是數字一組,后面包含數字結尾的所有分組
import re
s=re.findall(r'(?P\d+)(?<=\d)','987java678abc891abe2345stu2454dy')#結果是:['987', '678', '891', '2345', '2454']
#下面匹配前面是字母一組,后面包含字母的所有分組
s=re.findall(r'(?P\D+)(?<=\D)','java678abc891abe2345stu2454dy')#結果是:['java', 'abc', 'abe', 'stu', 'dy']
九、 后置否定分組,(?#后置否定(?<=pattern)
#下面匹配前面是數字一組,后面不包含字母的所有分組
s=re.findall(r'(?P\d+)(?
#下面匹配前面是字母一組,后面不包含數字的所有分組
s=re.findall(r'(?P\D+)(?
十、 消耗—不捕獲-不參與分組的圓括號,(?:pattern)
1、 實現需求
參與匹配,不捕獲,即不返回結果,不將匹配結果送給后面
類比前置肯定匹配(?=pattern)也不捕獲結果,但將匹配結果送給后面分組
2、 示例如下str='''
s=http://www-1.baidu.com
s=https://www-2.baidu.com
s=ftp://www-3.baidu.com
'''
#請注意,下面的str后面,沒有re.S,否則操作有錯,這里只對每一行進行正則匹配捕獲
s1=re.findall(r'(?:http|https|ftp):\/\/(?P.*)',str)
#結果是:['www-1.baidu.com', 'www-2.baidu.com', 'www-3.baidu.com']
s1=re.findall(r'(?:http|https|ftp)(?P:\/\/.*)',str)
#結果是:['://www-1.baidu.com', '://www-2.baidu.com', '://www-3.baidu.com']
s1=re.findall(r'(http|https|ftp):\/\/(?P.*)',str)
#結果是:[('http', 'www-1.baidu.com'), ('https', 'www-2.baidu.com'), ('ftp', 'www-3.baidu.com')]
s1=re.findall(r'(?:https:)(?P.*)',str,re.I)
#結果是:['//www-2.baidu.com']
十一、 前置—后置位置顛倒及對比(?:pattern)
1、 實現需求
r‘…(?<=pattern1)mypattern(?=pattern2) …’
將后置放在前面,將前置放在后面,結果是
(?<=pattern1)后置參與匹配、不捕獲、消耗
(?=pattern2)前置參與匹置、不捕獲、消耗
2、 語法結果理解
1) 將后置放在前面時
因為他只參與后置前一個正則表達式的匹配、捕獲、消耗,所以不參與
2) 將前置放在后面時
因為前置只參與他后面的一個前置,對后面的內容捕獲,所以本段內容匹配、消耗、不捕獲
3) mypattern有無分組,即圓括號,結果是一樣的
4) 實際測試時,如果mypattern有圓括號,則此時的前置顛到效果與加入(?:pattern)一樣
3、 示例如下#前置肯定與后置肯定顛倒顛顛位置后,則匹配、不捕獲、消耗
import re
str = r'
學習大數據bigData
's1 = re.findall(r"(?<=
).+?(?=
)",str)#前置與后置顛倒時,則只匹配、不捕獲,可以理解為后置己經參與前面一個正則的捕獲了,而前置放在后面,則對前面來說,不捕獲結果
#結果是:['學習大數據bigData']
s1 = re.findall(r"(?:
).+?(?=
)",str)#結果是:['
學習大數據bigData'],說明(?:pattern)不參與分組,但后面無分組時,則參與消耗
s1 = re.findall(r"(?:
)(?P.+?)(?=
)",str)#結果是:['學習大數據bigData'],說明(?:pattern)不參與分組,但后面有分組時,則不參與消耗
s1 = re.findall(r"(?:
)(?P.+?)(?:
)",str)#結果是:['學習大數據bigData'],說明(?:pattern)不參與分組,前后有分組時,則不參與消耗
s1 = re.findall(r"(?=
).+?(?=
)",str)#結果是:['
學習大數據bigData'],前置發揮正常作用,前置放在后面時,匹配,不對前面消耗
s1 = re.findall(r"(?:
).+?(?=
)",str)#結果是:['
學習大數據bigData'],說明(?:pattern)對后面無分組時,參與捕獲、消耗
s1 = re.findall(r"(?:
)(.+?)(?=
)",str)#結果是:['學習大數據bigData'],說明(?:pattern)對后面有分組時,消耗、但不參與捕獲
created by 劉明
總結
以上是生活随笔為你收集整理的python3.7正则表达式语法_python3正则表达式的几个高级用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 摄像头图像分析目标物体大小位置_小目标检
- 下一篇: python函数修饰器_Python函数