深入Python中的正則表達(dá)式
正則表達(dá)式應(yīng)用的場(chǎng)景也非常多。常見的比如:搜索引擎的搜索、爬蟲結(jié)果的匹配、文本數(shù)據(jù)的提取等等都會(huì)用到,所以掌握甚至精通正則表達(dá)式是一個(gè)硬性技能,非常必要。
正則表達(dá)式
正則表達(dá)式是一個(gè)特殊的字符序列,由普通字符和元字符組成。元字符能幫助你方便的檢查一個(gè)字符串是否與某種模式匹配。
Python中則提供了強(qiáng)大的正則表達(dá)式處理模塊,即 re 模塊, 為Python的內(nèi)置模塊。
下面,我?guī)Т蠹襾硪粋€(gè)入門demo例子,代碼如下:
- import re
- reg_string = "hello9527python@wangcai.@!:xiaoqiang"
- reg = "hello"
- result = re.findall(reg,reg_string)
- print(result)
這里reg_string就是我們的普通字符,reg就是我們的元字符。
我們使用 re 模塊中的findall函數(shù),進(jìn)行匹配,返回的結(jié)果是列表數(shù)據(jù)類型。
我們使用正則表達(dá)式,就是為了在很長的字符串中,找到我們需要的字符串片段。
元字符
Python中常見元字符及其含義如下:
下面,我們具體使用下Python中的常見的元字符。
我們還是使用上次的例子,這次我們需要在reg_string匹配出我們的數(shù)字,只需要將reg換成\d,代碼如下圖所示。
比如,我們?cè)谥暗膔eg的hello前面加上一個(gè)^,意味著我們 匹配字符串的開始的hello,那么結(jié)果就是一個(gè),就是我們開頭的hello。
如果,我們把reg換成\w,代碼如下圖所示。
這樣就是匹配數(shù)字字母下劃線,包括我們的漢字。
反義代碼
Python中常見反義代碼 及其含義如下:
其實(shí),記憶很簡(jiǎn)單,我們是不是知道\d匹配數(shù)字,那么\d的大寫\D就是匹配非數(shù)字,元字符[a]匹配a任意字符,那么[^a]就是匹配除了a以外的任意字符。
下面是具體例子
- >>> import re
- >>> reg_string = "hello9527python@wangcai.@!:xiaoqiang"
- >>> reg = "\D"
- >>> re.findall(reg,reg_string)
- ['h', 'e', 'l', 'l', 'o', 'p', 'y', 't', 'h', 'o', 'n', '@', 'w', 'a', 'n', 'g', 'c', 'a', 'i', '.', '@', '!', ':', 'x', 'i', 'a', 'o', 'q', 'i', 'a', 'n', 'g']
- >>> reg = "[^a-p]"
- ['9', '5', '2', '7', 'y', 't', '@', 'w', '.', '@', '!', ':', 'x', 'q']
限定符什么是限定符?就是限定我們匹配的個(gè)數(shù)的東西。
Python中常見限定符 及其含義如下:
我們還是用我們之前的reg_string,這次我們限定了元字符為\d{4},也就是我們的匹配的數(shù)字必須是4個(gè)。
下面,我們來提高難度,匹配字母和數(shù)字,限定個(gè)數(shù)為4個(gè)。
這樣我們可以使用[0-9a-z]{4},作為我們的元字符,[0-9a-z]代表了0到9的十個(gè)數(shù)字和a到z的小寫26個(gè)英文字母。[0-9a-z]{4}限定了個(gè)數(shù)為4個(gè)。
我們打印輸出下。
如果遇到了不是在[0-9a-z]范圍內(nèi),就會(huì)跳過,直到后面的4個(gè)都是在[0-9a-z]范圍內(nèi)就打印輸出。
匹配ip地址
在互聯(lián)網(wǎng)中,一臺(tái)主機(jī)只有一個(gè)IP地址。IP地址用于在TCP/IP通信協(xié)議中標(biāo)記每臺(tái)計(jì)算機(jī)的地址,通常用于十進(jìn)制來表示,如192.168.1.100。
在window系統(tǒng)中,我們可以通過ipconfig查看我們的ip。在linux系統(tǒng)中,我們可以通過ifconfig查看我們的ip。
我們的ip字符串是這樣子的:ip = "this is ip:192.168.1.123 :172.138.2.15"下面要求使用正則表達(dá)式,將ip匹配出來。
其實(shí),我們主要編寫元字符。比如:reg = "\d{3}.\d+.\d+.\d+",因?yàn)榈谝粋€(gè)數(shù)字必須是三位數(shù)開頭,我們可以設(shè)定\d{3}固定起來。
我們除了可以使用findall,還可以使用search,我們把元字符reg = "(\d{1,3}.){3}\d{1,3}"。
這元字符中的\d{1,3}.指定是我們ip前三個(gè)數(shù)字,后面加{3}就是重復(fù)3次。\d{1,3}指的就是我們ip最后一個(gè)數(shù)字。
但是search和findall是有區(qū)別的,search只能匹配第一個(gè),我們需要使用列表取出第一個(gè),而findall匹配所有。
組匹配
什么是組匹配,比如說這里邊我有一個(gè)字符串s = this is phone:13888888888 and this is my postcode:012345,我需要你把手機(jī)號(hào)和驗(yàn)證碼匹配出來。
因?yàn)?,我們要匹配兩個(gè),而已每個(gè)的元字符都是不一樣的。所以,我們需要分組匹配。
正則表達(dá)式的括號(hào)表示分組匹配,括號(hào)中的模式可以用來匹配分組的內(nèi)容。
于是我們的元字符就變成:reg = this is phone:(\d{11}) and this is my postcode:(\d{6})我們一般使用search進(jìn)行分組匹配,上次我是不是說過search需要使用列表取出來,這里的組匹配也是一樣,不過這里用的是group()方法。group(1)代表了我們的手機(jī)號(hào),group(2)代表了我們的驗(yàn)證碼,而group(0)代表了我們的手機(jī)號(hào)和驗(yàn)證碼,代碼如下圖所示。
在正則表達(dá)式中,除了findall和search用法,還有一個(gè)match用法。
match用法只匹配開頭的,也是需要group()取出來,下圖match的例子。
這是的re.I是忽略大小寫的意思。
貪婪與非貪婪
貪婪與非貪婪模式影響的是被量詞修飾的子表達(dá)式的匹配行為,貪婪模式在整個(gè)表達(dá)式匹配成功的前提下,盡可能多的匹配,而非貪婪模式在整個(gè)表達(dá)式匹配成功的前提下,盡可能少的匹配。
貪婪和非貪婪有幾個(gè)非常重要的操作符。
比如說這里邊我有一個(gè)字符串reg_string = pythonnnnnnnnnpythonHelloPytho,我們先使用貪婪的模式下的元字符:reg = "python*"
貪婪模式下的reg = "python*",意味著n重復(fù)零次或更多次。所以我們看到了第一關(guān)結(jié)果的pythonnnnnnnnn盡可能多的匹配。
下面使用非貪婪的模式下的元字符:reg = "python*?",reg = "python+?",reg = "python??"。
非貪婪模式下的reg = "python*",意味著n零次或一次,所以我們沒有看到pythonnnnnnnnn的結(jié)果。
手機(jī)號(hào)碼驗(yàn)證首先,我們要知道我們的手機(jī)號(hào)碼是什么開頭的?
移動(dòng)手機(jī)號(hào)碼開頭有16個(gè)號(hào)段:134、135、136、137、138、139、147、150、151、152、157、158、159、182、187、188。
聯(lián)通手機(jī)號(hào)碼開頭有7種號(hào)段:130、131、132、155、156、185、186。
電信手機(jī)號(hào)碼開頭有4個(gè)號(hào)段:133、153、180、189。
這樣我們就可以在開頭做事情了,先判斷開頭是不是上面的號(hào)段,regex = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}$",就是我們的元字符,代碼如下:
- import re
- def checkCellphone(cellphone):
- regex = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}$"
- result = re.findall(regex,cellphone)
- if result:
- print("匹配成功")
- return True
- else:
- print("匹配失敗")
- return False
- cellphone = '13717378202'
- checkCellphone(cellphone)
- 匹配成功
- True
匹配郵箱合法性
下面,我們進(jìn)行一個(gè)作業(yè),就是來匹配我們的郵箱號(hào)碼。
作業(yè)的答案如下:
- import re
- def checkEmail(email):
- regex_1 = '^(\w+)@sina.com$'
- regex_2 = '^(\w+)@sina.com.cn$'
- regex_3 = '^(\w+)@163.com$'
- regex_4 = '^(\w+)@126.com$'
- regex_5 = '^[1-9][0,9]{4,}+@qq.com$'
- regex = [regex_1 ,regex_2 ,regex_3, regex_4, regex_5]
- for i in regex:
- result = re.findall(i,email)
- if result:
- print("匹配成功")
- return True
- else:
- print("匹配失敗")
- return False
- email = 'sdjflsdjkl@sina.com'
- checkEmail(email)
正則表達(dá)式測(cè)試工具
打開開源中國提供的正則表達(dá)式測(cè)試工具 http://tool.oschina.net/regex/,輸入待匹配的文本,然后選擇常用的正則表達(dá)式,就可以得出相應(yīng)的匹配結(jié)果了。
例如,輸入下面這段待匹配的文本:
- Hello, my phone number is 123455678 and email is runsen@qq.com, and my website is https://blog.csdn.net/weixin_44510615.
這段字符串中包含了一個(gè)電話號(hào)碼和一個(gè)電子郵件,接下來就嘗試用正則表達(dá)式提取出來,如圖所示。
在網(wǎng)頁右側(cè)選擇 “匹配 Email 地址”,就可以看到下方出現(xiàn)了文本中的 E-mail。如果選擇 “匹配網(wǎng)址 URL”,就可以看到下方出現(xiàn)了文本中的 URL。是不是非常神奇?
本文已收錄 GitHub,傳送門~[1] ,里面更有大廠面試完整考點(diǎn),歡迎 Star。