正則表達式

正則表達式是處理字符串的強大工具,他有自己特定的語法結構

常用匹配規則

\w  匹配字母,數字及字符串
\W  匹配不是數字,字母及字符串的字符
\s  匹配任意空白字符,
\S  匹配任意非空白字符
\d  匹配任意數字
\D  匹配任意非數組的字符
\A  匹配字符串開頭
\Z  匹配字符串結尾,如果存在換行,只匹配到換行前的結束字符串
\z  匹配字符串結尾,如果存在換行,同時還會匹配到換行符
\G  匹配最後匹配完成的位置
\n  匹配一個換行符
\t  匹配一個製表符
^  匹配一個字符串的開頭
$  匹配一個字符串的結尾
.  匹配任意字符,除了換行符.當re.DOTAKLL標記被指定時,則可以匹配包括換行符的任意字符
[...]

 用來表示一組字符,單獨列出,比如[amk]匹配a,m或者k

[^...]

不再[]中的字符, [^amk]匹配除了a,m,k之外的字符

*  匹配0個或者多個表達式
+  匹配一個或者多個表達式
?  匹配0個或一個前面正則表達式定義的片段,非貪婪方式
{n}  精確匹配n個前面的表達式
{n,m}  匹配n到m次由前面正則表達式定義的片段,貪婪方式
a|b  匹配a或者b
()  匹配括號內的表達式,也表示一個組

 

正則表達式不是python獨有的,但是python的re庫提供了整個正則表達式的實現

import re
content = "hello 123 4567 Word_this a Regex Demo"
result = re.match("^hello\s\d\d\d\s\d{4}\s\w{10}",content)

print(result) #<_sre.SRE_Match object; span=(0, 25), match='hello 123 4567 World_This'>

print(result.group()) #hello 123 4567 World_This

print(result.span()) #(0, 25)

match()方法會嘗試從字符串的起使位置匹配正則表達式,如果匹配,返回匹配成功的結果,如果不匹配,返回None

在match()方法中,第一個參數傳入正則表達式,第二個參數傳入了要匹配的字符串,

打印輸出結果,可以看到結果是SRE_Match對象,有兩個方法:

group()方法可以輸出匹配到的內容

span()方法可以輸出匹配的範圍,

 

匹配目標

可以使用()將想要提取的子字符串擴起來

conent = "hello world 123456789 haha"
result = re.match("^hello\s\w{5}\s(\d+)\shaha",content)

print(result) #<_sre.SRE_Match object; span=(0, 26), match='hello world 123456789 haha'
print(result.group()) #hello world 123456789 haha
print(result.group(1)) #123456789

這裏我們想把字符串中的123456789提取出來,此時可以將數字部分的正則表達式用()擴起來.然後調用group(1)獲取匹配結果

假如正則表達式後面還有()包括的內容,可以依此使用group(2),group(3)等來獲取

 

通用匹配

剛纔我們用\s表示空白字符,\w表示字母,\d表示,其實完全沒有必要那麼做

萬能匹配:那就是.*(點星) .(點)可以匹配任意字符 *(星)代表匹配前面的字符無限次,

他們組合到一起就可以匹配任意字符了

 

貪婪與非貪婪

content = "hello world 123456789 haha"
result = re.match("^he.*(\d+).*ha$",content)

print(result) #<_sre.SRE_Match object; span=(0, 26), match='hello world 123456789 haha'>
print(result.group(1)) #9

奇怪的事情發生了,爲什麼只獲得了9這個數字呢

在貪婪模式下 .* 會儘可能的匹配多的字符,上面的例子中,.*後面是\d+,也就是最少一個數字,因此.*就會儘可能多的匹配,只留下了一個數字

非貪婪模式的寫法是.*?

content = "hello world 123456789 haha"
result = re.match("^he.*?(\d+).*?ha$",content)

print(result) #<_sre.SRE_Match object; span=(0, 26), match='hello world 123456789 haha'>

print(result.group(1)) #123456789

在做匹配的時候,字符串中間儘量使用非貪婪模式也就是用.*?來代替.*

content = "http://www.baidu.com/s?wd=python"
result = re.match("^http.*?.com.*?",content)
print(result) #<_sre.SRE_Match object; span=(0, 20), match='http://www.baidu.com'>

但這裏需要注意,如果匹配的結果在字符串結尾,  .*?可能匹配不到任何內容

 

修飾符

re.I  使匹配對大小寫不敏感
re.L  做本地化識別(locale-aware)匹配
re.M  多行匹配,影響^和$
re.S  使.(點)匹配包括換行在內的所用字符
re.U  根據Unicode字符集解析字符,這個標誌影響\w\W\b\B
re.X  該標誌通過給予你更靈活的格式以便你將正則表達式寫的更易於理解
content = '''hello
123456789 world
'''
result = re.match("^he.*?(\d+).*",content)
print(result) #None

result = re.match("^he.*?(\d+).*",content,re.S)
print(result) #<_sre.SRE_Match object; span=(0, 23), match='hello \n123456789 world\n'>

 

轉義匹配

當遇到用於正則匹配模式的特殊字符時,在前面加反斜線轉義一下即可

content = "(百度)http://www.baidu.com"
result = re.match("\(百度\)http:\/\/www\.baidu\.com",content)

print(result) #<_sre.SRE_Match object; span=(0, 24), match='(百度)http://www.baidu.com'>

 

 

.search()方法匹配的時候會掃描整個字符串,然後返回第一個成功匹配的結果,如果沒有找到,返回None

爲了匹配方便,儘量使用search()方法

>>> html = '''
... <div id="songs-list">
... <h2 class="title">經典老歌</h2>
... <p class="introduction">
... 經典老歌列表
... </p>
... <ul>
... <li data-view="2">一路上有你</li>
... <li data-view="7">
... <a href="/2.mp3" singer="任賢齊">滄海一聲笑</a>
... </li>
... <li data-view="4" class="active">
... <a href="/3.mp3" singer="齊秦">往事隨風</a>
... </li>
... </ul>
... </div>
... '''

result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S)

print(result.group(1)) #齊秦
print(result.group(2)) #往事隨風

由於絕大部分html文本都包含換行符,所以儘量都需要re.S修飾符,以免出現匹配不到的情況

 

 

前面我們介紹的search()方法,可以返回匹配的第一個結果, 。 如果想要獲取匹配正則表達式的所有內容,那就要藉助findall()方法了

result = re.findall('<li.*?href="(.*?)"\ssinger="(.*?)">(.*?)</a>',html,re.S)

print(result) #[('/2.mp3', '任賢齊', '滄海一聲笑'), ('/3.mp3', '齊秦', '往事隨風')]

print(result[0]) #('/2.mp3', '任賢齊', '滄海一聲笑')

print(result[1]) #('/3.mp3', '齊秦', '往事隨風')

可以看到,返回的列表中的每個元素都是元組類型,我們用對應的索引依此取出即可

 

我們還可用正則表達式sub()方法來修改文本

用第二個參數,替換掉第一個參數,第三個參數,是原字符串

>>> content = '12abr1g52ds34fge56'
>>> content = re.sub('\d+','',content)
>>> print(content)
abrgdsfge
>>> 

通過上面的例子來去除數字

 

 

compile()將正則字符串編譯成正則表達式對象,以便在後面的匹配中使用

import re
content1 = '2018-06-07 10:26'
content2 = '2018-06-07 10:27'
content3 = '2018-06-07 10:28'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, '',content1)
result2 = re.sub(pattern, '',content2)
result3 = re.sub(pattern, '',content3)
print(result1,result2,result3)

#2018-06-07  2018-06-07  2018-06-07

另外compile()還可以傳入修飾符,這樣在search(),findall(),等方法中就不需要額外傳了,

compile()方法可以說是給正則做了表達式做了一層封裝,以便我們更好的複用

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章