什么是正則表達式?
正則表達式(Regular Expression)留拾,又稱規(guī)則表達式涕侈,通常被用來檢索、替換那些符合某個模式(規(guī)則)的文本秒旋。許多程序設(shè)計語言都支持利用正則表達式進行字符串操作约计。
Python 自1.5版本起增加了re 模塊,它提供 Perl 風(fēng)格的正則表達式模式迁筛。re 模塊使 Python 語言擁有全部的正則表達式功能煤蚌。
正則表達式的使用對特殊字符進行了轉(zhuǎn)義,所以如果我們要使用原始字符串,只需加一個 r 前綴尉桩。
元字符
正則表達式由一些普通字符和一些元字符(metacharacters)組成筒占。普通字符包括大小寫的字母和數(shù)字,而元字符則具有特殊的含義蜘犁。下列為一些常見的元字符的使用說明翰苫。
匹配邊界:
^ 匹配行首
$ 匹配行尾
重復(fù)次數(shù):
? 重復(fù)匹配0次或1次
* 重復(fù)匹配0次或更多次
+ 重復(fù)匹配1次或更多次
{n} 重復(fù)n次
{n,} 重復(fù)n次或更多次
{n,m} 重復(fù)n~m次
各種字符的表示:
. 匹配除了換行符以外的任意字符串
[a-z] 任意a-z的字母
[abc] a,b,c中任意字符
\d 匹配數(shù)字
\D 匹配任意非數(shù)字的字符
\w 數(shù)字这橙,字母奏窑,下劃線
\W 匹配任意不是字母,數(shù)字屈扎,下劃線的字符
\s 空白字符(回車埃唯,制表,空格)
\S 匹配任意不是空白符的字符
\b 單詞的邊界
\B 匹配不是單詞開始和結(jié)束的位置
其他:
[^123abc] 匹配除了123abc這幾個字符以外的任意字符
123|abc 匹配123或者abc
Pattern 對象
compile 函數(shù)用于編譯正則表達式助隧,生成一個正則表達式( Pattern )對象筑凫,供 re 模塊的查找方法使用。語法格式為:
pattern = re.compile(r'正則表達式'并村,'匹配模式')
# 常用的匹配模式:
# re.S 可以讓 . 匹配換行符
# re.I 忽略大小寫
# re.M 多行匹配巍实,影響 ^ 和 $
單次匹配
re 模塊中,有兩個方法哩牍,match 函數(shù)和 search 函數(shù)棚潦,這兩個函數(shù)都是單次匹配,都返回一個
Match 對象膝昆。
re.match(pattern, string, start, end)
# pattern.match(string, start, end)
re.search(pattern, string, start, end)
# pattern.match(string, start, end)
# pattern 正則表達式對象
# string 要匹配的目標(biāo)字符串
# start 要匹配的目標(biāo)字符串的起始位置(可選)
# end為 要匹配的目標(biāo)字符串的結(jié)束位置(可選)
"""案例"""
import re
pattern = re.compile(r'\w+', re.I)
string = 'I love python'
result = pattern.match(string, 2, 6)
print(result)
# <re.Match object; span=(2, 6), match='love'>
print(result.group())
# love
需要注意的是丸边,match 函數(shù) 只匹配字符串的開始,如果字符串開始不符合正則表達式荚孵,則匹配失敗妹窖,函數(shù)返回 None,而 search 函數(shù)是匹配整個字符串收叶,直到找到一個匹配骄呼。
import re
string = 'i am 18 !!!'
result1 = re.match(r'\d+', string)
result2 = re.search(r'\d+', string)
print(result1)
# None
print(result2.group())
# 18
分組
在Python中,正則表達式分組就是用一對圓括號“()”括起來的正則表達式判没,匹配出的內(nèi)容就表示一個分組蜓萄。即每個圓括號都是一個分組,從1開始澄峰。需要注意的是嫉沽,有一個隱含的全局分組(就是0),也就是整個正則表達式俏竞。
import re
pattern = re.compile(r'name is (.*),age:(\d+)', re.I)
string = 'my name is 啊哈哈君,age:18 !'
result = pattern.search(string)
print(result)
# <re.Match object; span=(3, 22), match='name is 啊哈哈君,age:18'>
print(result.group())
# name is 啊哈哈君,age:18
print(result.group(1))
# 啊哈哈君
print(result.group(2))
# 18
Match 對象
關(guān)于match函數(shù)和search函數(shù)返回的match對象绸硕,也是有很多方法可以調(diào)用的堂竟。如上述案例的group函數(shù),會返回被匹配的字符串臣咖。
# 返回被匹配的字符串跃捣,等價于group(0)
Match.group()
# 返回第n個分組匹配的字符串,如果組號不存在夺蛇,則返回indexError異常
Match.group(n)
# 返回組號為n到m組所匹配的字符串的元組疚漆,如果組號不存在,則返回indexError異常
Match.group(n,m)
# 返回所有分組匹配的字符串的元組
Match.groups()
# 返回匹配開始的位置
Match.start()
# 返回匹配結(jié)束的位置
Match.end()
# 返回一個元組包含匹配 (開始,結(jié)束) 的位置
Match.span()
多次匹配
re 模塊中的findall函數(shù)與finditer函數(shù)用于進行多次匹配刁赦。相信通過函數(shù)名娶聘,有些小伙伴就可以知道這兩個函數(shù)的返回值。
import re
string = 'abcdefg'
result1 = re.findall(r'\w', string)
result2 = re.finditer(r'\w', string)
print(result1)
# ['a', 'b', 'c', 'd', 'e', 'f', 'g']
print(result2)
# <callable_iterator object at 0x000002452F017848>
由上述案例可看出甚脉,多次匹配與單次匹配的函數(shù)用法相同丸升,也可以加start和end。只是findall函數(shù)返回的是一個列表牺氨,而finditer返回的是一個迭代器狡耻。
分割字符串
re 模塊提供了一個spilt函數(shù),用于通過正則表達式分割字符串猴凹,并返回一個列表夷狰。
import re
pattern = re.compile(r'\s', re.I)
string = 'python java c++'
result = pattern.split(string)
print(result)
# ['python', 'java', 'c++']
替換字符串
re 模塊中的sub函數(shù)用于通過正則表達式替換字符串。格式為:
re.sub(pattern, repl, string, count)
# pattern.sub(repl, string, count)
# pattern 正則表達式或者正則對象
# repl 替換的字符串郊霎,也可為一個函數(shù)
# string 要被查找替換的原始字符串
# count 匹配后替換的最大次數(shù)沼头,默認為0,表示替換所有的匹配
這個函數(shù)通過案例是很容易理解的书劝。
import re
pattern = re.compile(r'python', re.I)
string = 'I Love Python, Python NB!'
result1 = pattern.sub('java', string)
result2 = pattern.sub('java', string, 1)
print(result1)
# I Love java, java NB!
print(result2)
# I Love java, Python NB!
當(dāng)repl為函數(shù)時进倍,函數(shù)的參數(shù)只能為match對象,并且這個函數(shù)必須有返回值购对,返回值的格式是字符串猾昆,將來就用這個字符串作為替換的內(nèi)容。
import re
pattern = re.compile(r'python', re.I)
def func(matched):
return matched.group()+' And Java'
string = 'I Love Python'
result = pattern.sub(func, string)
print(result)
# I Love Python And Java
貪婪模式與非貪婪模式
貪婪匹配:正則表達式一般趨向于最大長度匹配骡苞,也就是所謂的貪婪匹配毡庆。
非貪婪匹配:就是匹配到結(jié)果就好,取最少的匹配字符烙如。
在Python中,默認是貪婪模式毅否,而在正則表達式的量詞后面直接加上一個問號亚铁?就會轉(zhuǎn)換為非貪婪模式。
import re
string = 'i am 18 螟加!'
result1 = re.search(r'\d+', string)
result2 = re.search(r'\d+?', string)
print(result1.group())
# 18
print(result2.group())
# 1
在上述案例中的正則為\d+徘溢,也就是匹配數(shù)字1次或多次吞琐。也就是說,在貪婪模式下然爆,這個正則會往多的次數(shù)匹配站粟,也就是優(yōu)先多次,即匹配到了18曾雕,而非貪婪模式下奴烙,則會優(yōu)先匹配1次,也就是優(yōu)先匹配到了1剖张,滿足條件便會立刻返回結(jié)果切诀。