??正則是做數(shù)據(jù)分析和挖掘必須要會(huì)的一種方法,會(huì)了它很多問題其實(shí)就可以高效的解決了。說一個(gè)最常用的應(yīng)用場(chǎng)景,在文本識(shí)別中,使用正則可以快速識(shí)別出類似于qq號(hào)、廣告、聯(lián)系方式等內(nèi)容,很簡(jiǎn)單就可以為網(wǎng)站文本過濾提供支持。
1.正則表達(dá)式基礎(chǔ)
??正則表達(dá)式有一套自己的語言系統(tǒng),像人類語言一樣,有幾個(gè)關(guān)鍵字構(gòu)成了它的基礎(chǔ)語法。整理起來就是下面這幾個(gè):
- \表示轉(zhuǎn)義,一些特殊字符有特殊的意識(shí),加\就可實(shí)現(xiàn)特定的意思。比如\d表示匹配數(shù)字,\s表示匹配任何不可見字符,如空格、制表符等。
- .表示匹配任意字符,要匹配.自身,就需要轉(zhuǎn)義用\.。
- *表示匹配前面的字符0次或者多次,即即使一次不出現(xiàn)也無所謂。
- +表示匹配前面的字符1次或者多次,即前面的字符至少要出現(xiàn)1次。
- ?表示匹配前面的字符0次或者1次。
- |表示或,可以匹配|前后的任意字符。
- ^表示匹配字符串的開始位置,必須以^之后的字符開頭的才能匹配。
- $表示匹配字符串的結(jié)尾位置,必須以$之前字符結(jié)尾的才能匹配。
- [^]當(dāng)^出現(xiàn)在方括號(hào)里表示匹配非方括號(hào)內(nèi)的任意一個(gè)字符。
- {}表示匹配前面的字符幾次,{3}表示匹配3次,{3,5}表示匹配3-5次,可以和[]一起使用。
- <>匹配單詞,如<the>可以匹配 the man中的the,卻不能匹配otherwise中的the。
- ()表示匹配一個(gè)整體,即括號(hào)里的內(nèi)容必須都出現(xiàn)的時(shí)候才匹配,關(guān)于()還有很多衍生,實(shí)際中也比較有用。
- (?:)非獲取匹配,就是只匹配內(nèi)容但卻不輸出,這個(gè)在re模塊的fetchall中最常用,比如說industr(?:y|ies)這個(gè)能匹配industry也能匹配y但是最后只會(huì)輸出industry而不輸出y。
- (?=pattern)這個(gè)也是非獲取匹配,大意是先找pattern然后看之前的字符串符不符合正則,匹配完成后進(jìn)行下一次的pattern匹配,也是只輸出整體,而不單獨(dú)輸出pattern。比如Windows(?=95|98|NT|2000)能匹配Windows2000中的Windows而不能匹配Windows7中的Windows。
- (?!pattern)這個(gè)和上面那個(gè)正好相反,在不匹配pattern的位置開始查找字符串。比如Windows(?=95|98|NT|2000)能匹配Windows7中的Windows而不能匹配Windows2000中的Windows。
- (?<=pattern)這個(gè)東西太有意思了,和(?=pattern)是一樣的,只不過方向是反的,啥意思呢,(?<=95|98|NT|2000)Windows)能匹配2000Windows里的Windows,卻匹配不了7Windows里的Windows。
- (?<!pattern),我想你已經(jīng)猜到了,和(?!pattern)相同,只是方向是反的,例子我就不舉了。
??會(huì)了這些,正則表達(dá)式你就入門了,剩下的看你的悟性了。
2.正則表達(dá)式常用元字符
??其實(shí)第一部分講的也是元字符,之所以把它們拿出來說是因?yàn)樘匾耍绻麑?duì)正則要求不咋嚴(yán)格的話,第一部分就足夠解決大部分問題了。下面的我就簡(jiǎn)單介紹。
- \b,匹配單詞邊界,如od\b,可以匹配good,但不能匹配odd。
- \B,匹配非單詞邊界,如od\B,可以匹配odd,但不能匹配good。
- \d,匹配一個(gè)數(shù)字,等同于[0-9]。
- \D,匹配一個(gè)非數(shù)字,等同于[^0-9]。
- \r,匹配回車符。
- \n,匹配換行符,經(jīng)常和\r一起用。
- \f,匹配分頁符。
- \t,匹配制表符。
- \s,匹配任何不可見的字符,包括空格,回車符,換行符等。
- \S,匹配任何可見字符。
- \w,匹配包括下劃線的任意字母數(shù)字字符。
-\W,匹配非下劃線、數(shù)字、字母字符。 - \p{P},匹配任意標(biāo)點(diǎn)符號(hào),還有其他的用法:L字母;M:標(biāo)記符號(hào)(一般不會(huì)單獨(dú)出現(xiàn));Z:分隔符(比如空格、換行等);S:符號(hào)(比如數(shù)學(xué)符號(hào)、貨幣符號(hào)等);N:數(shù)字(比如阿拉伯?dāng)?shù)字、羅馬數(shù)字等);C:其他字符。這個(gè)原生的python re包是不支持的,需要安裝regex包才支持,這個(gè)包有很多高階用法,我后面介紹。
??當(dāng)然還有很多表達(dá)方式,不過不經(jīng)常使用,如果要用的話可以去百度。
3.python中自帶的處理正則表達(dá)式的包—re
??開始之前,先說一下python對(duì)字符串的默認(rèn)操作符,首先是字符串前加r,表示不轉(zhuǎn)義,r"i am . frank",這個(gè)點(diǎn)就是代表點(diǎn)自身,還有一個(gè)是字符串前加u,代表采用unicode編碼,對(duì)于中文的正則用的比較多。接下來說re中的函數(shù)。
- re.compile()
??這個(gè)函數(shù)是對(duì)你寫好的正則進(jìn)行編譯,用法就是compile(pattern, flags=0) ,它要和下面的函數(shù)搭配使用才能起作用。但是首先編譯你寫好的正則表達(dá)式是一種良好的編碼習(xí)慣,可以使代碼更整潔。 - re.match()
??這個(gè)函數(shù)是根據(jù)寫好的字符查找字符串中符合條件的部分,基本用法為re.match(pattern,str),要求必須從字符串的開頭開始匹配,要提取值,可以用result.group()。這個(gè)得舉例子來說了。
import re
regx1 = re.compile('\w{0,8}')
result = re.match(regx1,'itcast.cn')
#當(dāng)然也可以用result = re.match('\w{0,8}','itcast.cn')
print(result)
-- 輸出,注意它的輸出是一個(gè)python對(duì)象,可以當(dāng)邏輯判斷使用
<re.Match object; span=(0, 6), match='itcast'>
- re.search()
跟match作用類似,所不同的是不要求必須從字符串開頭開始匹配,也就是說可以匹配字符串的任意位置,返回第一個(gè)成功的匹配,基本用法為:re.search(pattern, string, flags=0)。
regx1 = re.compile('\d+')
result = re.search(regx1,'abc 123itcast.cn522abc')
print(result)
-- 輸出
<re.Match object; span=(4, 7), match='123'>
- re.findall()
??這個(gè)函數(shù)將以列表的形式返回所有匹配到的字符,因?yàn)榉祷氐氖亲址斜硭员萴atch函數(shù)要常用,基本用法為findall(pattern, string, flags=0),參數(shù)的含義和match一樣,還是來看案例。
regx2 = re.compile('[t,w]h')
result = re.findall(regx2,'https://docs.python.org/3/whatsnew/3.6.html')
print(result)
--輸出
['th', 'wh']
??這個(gè)函數(shù)有個(gè)坑我必須要說一下,就是如果有括號(hào)的話,那么括號(hào)里的內(nèi)容都會(huì)匹配一遍。
regx3 = re.compile(r'(.*([w]h).*)')
result = re.findall(regx3,'https://docs.python.org/3/whatsnew/3.6.html')
print(result)
--輸出
[('https://docs.python.org/3/whatsnew/3.6.html', 'wh')]
??咋辦呢,用第一部分的?:解決。
regx4 = re.compile(r'(.*(?:[w]h).*)')
result = re.findall(regx4,'https://docs.python.org/3/whatsnew/3.6.html')
print(result)
--輸出
['https://docs.python.org/3/whatsnew/3.6.html']
- re.split()
??這個(gè)函數(shù)的作用是以寫好的正則表達(dá)式為分割符,對(duì)字符串進(jìn)行分割后以列表形式返回分割之后的結(jié)果。
regx4 = re.compile(r'\d+')
print(regx4.split('one1two2three3four4'))
-- 輸出
['one', 'two', 'three', 'four', '']
- re.sub()
??這是第一版介紹的最后一個(gè)函數(shù),這個(gè)函數(shù)的作用是替換,返回的是匹配之后的結(jié)果?;居梅閞e.sub(pattern, repl, string, count=0, flags=0)
,其中pattern,repl,string是必選參數(shù),repl的意思是用什么字符串去替換正則匹配到的字符串。
regx5 =re.compile( "\d+")
result = re.sub(regx5, '_add111', 'hello 123 world 456 nihao 789',2)
print(result)
--輸出
hello _add111 world _add111 nihao 789
??還有一些高階函數(shù),如果我用上了,我會(huì)繼續(xù)補(bǔ)充的,目前筆者工作中還是沒有遇到的。
4.3.python正則表達(dá)式進(jìn)階—regex
??這個(gè)包不是python自帶的,需要pip install安裝,安裝很簡(jiǎn)單。它提供了很多附加的正則表達(dá)式功能。
- 支持unicode代碼屬性,如u'[\u4e00-\u9fa5]'表示任意中文字符,\p{Cyrillic}表示西里爾字符,更多用法可以使用過程中百度。
- 支持模糊匹配,有三種模式:i,模糊插入、d,模糊刪除、s,模糊替換。
import regex
regex.findall('(?:hello){s<=2}', 'hallo')
--輸出
['hallo']
- 支持可以復(fù)用的程序子句,用(?(DEFINE)...)進(jìn)行操作
regex.search(r'(?(DEFINE)(?P<quant>\d+)(?P<item>\w+))(?&quant) (?&item)', '5 elephants')
-- 輸出
<regex.Match object; span=(0, 11), match='5 elephants'>
??此后可以用(?&quant)表示\d+,(?&item)表示\w+,特別適用于子句復(fù)雜的情況。
??更多功能待探索后補(bǔ)充。