python3基礎:正則(一)
簡介
正則是一個字串規則,本身也是一個字元型,用來檢查一個串是否含有字串。可以做精確匹配,模糊匹配,進行字串替換,切割,尤其是在造資料,分析日誌時用的非常多。
python中處理正則表示式的模組是re模組,正則表示式由一些普通字元和一些元字元組成,普通字元包括大小寫字母、數字和列印符號,而元字元是具有特殊含義的字元。
正則表示式模式
正則表示式大致的匹配過程是:
拿正則表示式依次和字串或者文字中的字串做比較,如果每一個字元都匹配,則匹配成功,只要有一個匹配不成功的字元,則匹配不成功。模式字串使用特殊的語法來表示一個正則表示式:
- 字母和數字匹配它們自身;
- 多數字母和數字前加一個反斜槓(\)時會有特殊含義;
- 特殊的標點符號,只有被轉義以後才能匹配自身;
- 反斜槓本身要用反斜槓來轉義
注意:
- 由於正則表示式通常版本反斜槓等特殊字元,所以最好使用原始字串來表示他們。如:r’\d’等價於’\\d’,表示匹配一個數字
- 正則表示式中數量詞預設都是貪婪的,會盡可能多的去匹配滿足的字串,但是如果在後面加上問號’?’,就可以遮蔽貪婪模式,表示匹配儘可能少的字元。如:’xyyyyzs’,使用正則’xy*’,就會得到'xyyyy',如果使用’xy*?’,會得到'x'
特殊表示式含義
符號 | 含義 |
舉例 |
一般字元(匹配自身) |
||
.(點) |
匹配除換行符之外的任意一個字元,DOTALL模式中可以匹配換行符 |
a.c可以匹配abc |
\(反斜槓) |
轉義一個特殊的字元,使這個字元表示原來字面上的意思。如"\$",表示原字元$,而不是正則表示式中表示匹配行尾的意思。 |
a\.c匹配a.c |
預定義字符集(可以寫在[]中) |
||
[...] 方括號 |
匹配括號中出現的任意單個字元 |
a[123]b匹配a1b、a2b、a3b、a12b等 |
[^...] |
不匹配方括號中列出的單個字元(注意只能針對單個字元) |
[^ab]匹配除a和b之外的字元 |
\d |
匹配中任意一個數字,範圍為[0-9] |
a\dc可以匹配a1c、a2c等 |
\D |
匹配任意一個非數字字元,等價於[^\d] |
1\D2可匹配1a2 |
\s |
匹配任意一個空白字元:[<空格>\t\r\n\v\f] |
a\sf匹配a f |
\S |
匹配任意一個非空白字元,等價於[^\s] |
a\Sg匹配agg等 |
\w |
匹配一個字母或數字,字元範圍:[A-Za-z0-9] |
1\wt可以匹配1at等 |
\W |
非單詞字元,等價於[^\w] |
a\Wb可以匹配[email protected]等 |
數量字符集(用在字元或分組符(...)之後,非貪婪匹配*? +?) |
||
*(星號) |
匹配前一個字元0次1次或多次 |
abc*可以匹配ab、abc、abcc等 |
+(加號) |
匹配前一個字元1次或多次 |
cde+可匹配cde、cde等 |
?(問號) |
匹配前一個字元0次或1次 |
fgh?匹配結果fg、fgh |
{m} |
匹配前一個字元m次 |
qc{3}匹配結果qccc |
{m,n} |
匹配前一個字元m到n次 {m,}匹配前一個字元至少m次 {,n}匹配前一個字元0到n次,最多n次 |
1{2,5}ac匹配結果11ac、111ac、1111ac、11111ac |
符號 |
含義 |
舉例 |
|
邊界匹配符 |
|||
^(託字元) |
匹配字串開頭,如果是多行則匹配每一行的開頭。在[...]中,^表示否定,如非字母[^a-zA-Z],非數字[^0-9] |
^123匹配123 a[^0-9]b可匹配aab等 |
|
$(美元符) |
匹配字串或一行的結尾,如果是多行則匹配每一行的結尾 |
abc$匹配abc |
|
\A |
匹配字串開始,如果存在換行,將字元當作一個整體 |
\A12AC匹配12AC |
|
\b |
匹配一個單詞的邊界,也就是指單詞和空格間的位置 |
\bst匹配a test中的'st',但不匹配'tester'中的''st |
|
\B |
[^\b],表示匹配非單詞邊界 |
\Bst可以匹配'tester'而不能匹配'test' |
|
\Z |
匹配字串結束,如果存在換行,將字元當作一個整體 |
abt\Z匹配abt |
|
邏輯匹配符 |
|||
|(或) |
|或匹配符,表達左右正則表示式任意匹配一個。如果左邊的表示式匹配上了,匹配結束,不再匹配右邊的表示式。該符號一般放在()中使用,如果沒在圓括號中則它的範圍是整個正則表示式。 |
(12|34)匹配12或34 |
|
分組匹配 |
|||
(...) |
後向引用。用()括起來的正則表示式將被作為一個分組,從正則表示式的左邊依次算起,有多少個左括號'(',就有多少個分組,分組的編碼從1依次加1,無論是括號中巢狀括號。並且分組表示式作為一個整體,後可接數量詞。 |
(xyz){2}滿足xyzxyz x(12|34)y匹配x12y或x34y |
|
\<number> |
引用分組匹配到的分組編號為<number>的字串 |
如:\1...\9 |
|
(?P<name>...) |
命名分組,除了預設的分組編號外再指定一個別名分組 注意:P是大寫 |
||
(?P=name) |
引用別名為name的分組匹配,這個是在正則表示式中引用,表示匹配重複的字串,也可以使用編號引用。 注意:P是大寫 |
||
特殊匹配符(不能作為分組使用) |
|||
(?:...) |
|||
(?!pattern) |
前向否定斷言語法,表示否定開頭。只能用在正則表示式的開頭,pattern是匹配模式,它後面的內容需要不匹配該正則表示式才匹配成功。 |
||
(?<!pattern) |
後向否定斷言語法,表示否定結尾,前面的內容需要不匹配該pattern模式才匹配成功。 |
||
(?=pattern) |
前向肯定斷言語法,需要匹配pattren模式才能匹配成功,表示肯定前面的字元內容。 |
||
(?<=pattern) |
後向肯定斷言語法,需要匹配pattern模式才能匹配成功,表示肯定後面的字元內容。 |
||
(?#...) |
#後面的內容將被作為註釋而忽略 |
.(點)
匹配除換行符之外的所有字元。可以在DOTALL模式中可以匹配換行符。
>>> import re
>>> re.match(r'.','and23__09')
<_sre.SRE_Match object; span=(0, 1), match='a'>#返回的是匹配結果的物件,span表示是是匹配的開始位置和結束位置,開區間
>>> re.match(r'..','and23__09')
<_sre.SRE_Match object; span=(0, 2), match='an'>
>>> re.match(r'..........','and23__09')#匹配的個數比字元中多的時候,返回的是None
>>> print(re.match(r'.','\n'))
None
>>> re.match(r'.','\n',re.DOTALL)#可以匹配換行符
<_sre.SRE_Match object; span=(0, 1), match='\n'>
多行字串的兩種實現方式:
三引號
>>> '''hello
... python
... 123'''
'hello\npython\n123'
單引號裡面包含\n
>>> print('abc\ndef')
abc
def
\(反斜槓)
>>> print(re.match(r"\.",".a\nc"))#匹配 .
<_sre.SRE_Match object; span=(0, 1), match='.'>
>>> print(re.match(r"\\","\\a\nc"))#匹配 \本身
<_sre.SRE_Match object; span=(0, 1), match='\\'>
[...]方括號:
匹配括號中指定的某一個字元,但是隻能匹配一個字元。
>>> print(re.match(r"[abc]","axxx")) #匹配字元a
<_sre.SRE_Match object; span=(0, 1), match='a'>
>>> print(re.match(r"[abc]","bxxx")) #匹配字元b
<_sre.SRE_Match object; span=(0, 1), match='b'>
>>> print(re.match(r"[abc]","cxxx")) #匹配字元c
<_sre.SRE_Match object; span=(0, 1), match='c'>
[^...]
不匹配括號中指定的任何一個字元,但是隻能匹配一個字元(注意^在方括號裡面表示非,在方括號外面表示開頭匹配)
>>> print(re.match(r"[^abc]","hxxx")) #匹配開頭是非abc之外的任意一個字元
<_sre.SRE_Match object; span=(0, 1), match='h'>
>>> print(re.search(r"abc","sssssabc")) #匹配abc,可以不是開頭
<_sre.SRE_Match object; span=(5, 8), match='abc'>
>>> print(re.search(r"^abc","sssssabc"))#匹配以abc開頭的字元
None
>>> print(re.match(r"\d","123"))#匹配一次
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> print(re.match(r"\d+","123"))#匹配一次或多次
<_sre.SRE_Match object; span=(0, 3), match='123'>
>>> print(re.match(r"\d*","123"))#匹配0次或多次
<_sre.SRE_Match object; span=(0, 3), match='123'>
\d
匹配中任意一個數字,範圍為[0-9]
>>> re.match(r"\d","123").group()
'1''
\D
匹配任意一個非數字字元,等價於[^\d]
>>> re.match(r"\D+","a123").group()
'a'
>>> re.match(r"\D+","abc123").group()
'abc'
\s
匹配任意一個空白字元:[<空格>\t\r\n\v\f]
>>> re.search(r'\s','anb \t \r \n')
<_sre.SRE_Match object; span=(3, 4), match=' '>
>>> re.search(r'\s+','anb \t \r \n')
<_sre.SRE_Match object; span=(3, 9), match=' \t \r \n'>
\S
匹配任意一個非空白字元,等價於[^\s]
>>> re.findall(r"\S+","ab cd\t ef\nhi")
['ab', 'cd', 'ef', 'hi']
>>> "".join(re.findall(r"\S+","ab cd\t ef\nhi")) #去掉了字串中所有的空白字元
'abcdefhi'
\w
匹配一個字母,數字和下劃線,字元範圍:[A-Za-z0-9_]
>>> re.search(r'\w','12bsc_-')
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>>
>>> re.search(r'\w+','12bsc_-')
<_sre.SRE_Match object; span=(0, 6), match='12bsc_'>
>>>
\W
非字母,數字和下劃線,等價於[^\w]
>>> re.search(r'\W+','12bsc_-')
<_sre.SRE_Match object; span=(6, 7), match='-'>
>>> re.search(r'\W+','[email protected]')
<_sre.SRE_Match object; span=(1, 2), match='@'>
*
匹配一個字元0次或多次,注意正則預設的貪婪性,貪婪性指的是在滿足匹配的條件下再繼續貪婪更多的匹配
>>> print(re.match(r"\d*","123"))
<_sre.SRE_Match object; span=(0, 3), match='123'>
>>> print(re.match(r"\d*?","123")) #用問號抑制貪婪,*最小是0次匹配
<_sre.SRE_Match object; span=(0, 0), match=''>
>>> print(re.match(r"\d+?","123"))#用問號抑制貪婪,+最小是1次匹配
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> print(re.search(r'\d*','abc123'))
<_sre.SRE_Match object; span=(0, 0), match=''>
search有匹配就會返回,字串不是數字開頭,匹配0次,所以返回的是空
?
匹配一個字元0次或1次,?用在數量詞(*/+/{m}/{m,n})後面才表示抑制貪婪性。
>>> re.search(r"\d?","a7").group() #不是以數字開頭,匹配了0次,所以返回空字元
''
>>> re.search(r"\d?","7").group() #以數字開頭,匹配了1次,所以返回7
'7'
+
匹配一個字元1次或多次,注意正則預設的貪婪性。
>>> s = "abc123dee"
>>> re.search(r'\d+',s)
<_sre.SRE_Match object; span=(3, 6), match='123'>
>>> re.search(r'\d+',s).group()
'123'
>>> re.search(r"\d+","7").group()
'7'
>>> print(re.match(r"\d+?","123"))#用問號抑制貪婪,+最小是1次匹配
<_sre.SRE_Match object; span=(0, 1), match='1'>
{}
匹配次數
{m}:匹配前一個字元m次
{m,n}:匹配前一個字元m到n次
{m,}匹配前一個字元至少m次
{,n}匹配前一個字元0到n次,最多n次
>>> re.search(r'\d{2}',"abc123dee").group()
'12'
>>> re.search(r"\d{3}","123456789").group()
'123'
>>> re.search(r"\d{1,3}","123456789").group() #貪婪性
'123'
>>> re.search(r"\d{1,3}?","123456789").group()
'1'
^(脫字元)
匹配字串開頭,如果是多行則匹配每一行的開頭。在[...]中,^表示否定,如非字母[^a-zA-Z],非數字[^0-9]
>>> re.search(r"^abc","dddabc")
>>> re.search(r"^abc","abcabc")
<_sre.SRE_Match object; span=(0, 3), match='abc'>
>>> re.search(r"^abc","abcde\nabc")
<_sre.SRE_Match object; span=(0, 3), match='abc'>
$(美元符)
匹配字串或一行的結尾,如果是多行則匹配每一行的結尾
>>> re.search(r"^\d+","133dddabc")
<_sre.SRE_Match object; span=(0, 3), match='133'>
>>> re.search(r"\d+$","133dddabc5555")
<_sre.SRE_Match object; span=(9, 13), match='5555'>
>>> re.search(r"^123$","123")
<_sre.SRE_Match object; span=(0, 3), match='123'>
\A
非多行匹配的時候等價於^,多行匹配的是\A將整個字串看做一個整體匹配,而^能夠則匹配每一行的結尾
>>> re.search(r"\Aabc","abcabc")
<_sre.SRE_Match object; span=(0, 3), match='abc'>
>>> s = '124\n453\n'
>>> re.search(r'^\d',s)
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> re.findall(r'^\d',s)
['1']
>>> re.findall(r'^\d',s,re.M) #匹配多行檔案每行的結尾
['1', '4']
>>> re.findall(r'\A\d',s,re.M) #即使加了re.M,使用\A時仍然是將字串看做一個整體
['1']
>>> re.findall(r'\A\d',s)#使用\A時仍然是將字串看做一個整體
['1']
\Z
非多行時等價於$,多行匹配\Z將整個字串看做一個整體匹配,而$能夠則匹配每一行的結尾。
>>> re.search(r"\A123\Z","123")
<_sre.SRE_Match object; span=(0, 3), match='123'>
>>> s = '124\n453\n'
>>> re.search(r'\d$',s)
<_sre.SRE_Match object; span=(6, 7), match='3'>
>>> re.search(r'\d\Z',s) #沒有匹配成功
>>> re.findall(r'\d$',s)
['3']
>>> re.findall(r'\d$',s,re.M) #匹配每一行的結尾
['4', '3']
>>> re.findall(r'\d\Z',s)
[]
>>> re.findall(r'\d\Z',s,re.M)#換行前的結束字元也不能匹配
[]
>>> s = '124\n453'
>>> re.findall(r'\d\Z',s,re.M)
['3']
>>> re.findall(r'\d\Z',s)
['3']
()分組
用()括起來的正則表示式將被作為一個分組,從正則表示式的左邊依次算起,有多少個左括號'(',就有多少個分組,分組的編碼從1依次加1,無論是括號中巢狀括號。並且分組表示式作為一個整體,後可接數量詞。
>>> re.search(r"\d(\D+)\d","1abc3").group(1)
'abc'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(1)
'1'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(2)
'abc'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(2)
'abc'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(3)
'3'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group()#表示正則表示式匹配的全部內容,等價於group(0)
'1abc3'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(0)
'1abc3'