5-正則匹配獲取數據


4,正則匹配-數據獲取

https://docs.python.org/zh-cn/3/library/re.html

正則表達式是對字符串操作的一種邏輯公式,事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符”,這個“規則字符” 來表達對字符的一種過濾邏輯

常見的正則表達式符號和特殊符號



\w      匹配字母數字及下划線
\W      匹配f非字母數字下划線
\s      匹配任意空白字符,等價於[\t\n\r\f]
\S      匹配任意非空字符
\d      匹配任意數字
\D      匹配任意非數字
\A      匹配字符串開始
\Z      匹配字符串結束,如果存在換行,只匹配換行前的結束字符串
\z      匹配字符串結束
\G      匹配最后匹配完成的位置
\n      匹配一個換行符
\t      匹配一個制表符
^       匹配字符串的開頭
$       匹配字符串的末尾
.       匹配任意字符,除了換行符,re.DOTALL標記被指定時,則可以匹配包括換行符的任意字符
[....]  用來表示一組字符,單獨列出:[amk]匹配a,m或k
[^...]  不在[]中的字符:[^abc]匹配除了a,b,c之外的字符
*       匹配0個或多個的表達式
+       匹配1個或者多個的表達式
?       匹配0個或1個由前面的正則表達式定義的片段,非貪婪方式
{n}     精確匹配n前面的表示
{m,m}   匹配n到m次由前面的正則表達式定義片段,貪婪模式
a|b     匹配a或者b
()      匹配括號內的表達式,也表示一個組

匹配一個或多個表達式

匹配字符或單詞邊界


字符集



星號或者星號操作符(*)將匹配其左邊的正則表達式出現零次或者多次的情況(在計算機編程語言和編譯原理中,該操作稱為 Kleene 閉包)。加號(+)操作符將匹配一次或者多次出現的正則表達式(也叫做正閉包操作符),問號(?)操作符將匹配零次或者一次出現的正則表達式

字符集特殊字符

分組

圓括號表示分組

擴展表示法

Python操作

re模塊

re 模塊:核心函數和方法

一些理論

1,原子
原子是正則表達式(模式pattern)中最基本的組成方式,每個正則表達式中,至少要包含一個原子,常見的原子分類:
普通字符作為原子 : 數字,大小寫字母,下划線
非打印字符作為原子 : 用於格式控制的字符 \n
通用字符作為原子 : \w \d
原子表 : [adb] [^adgk]

2,元字符
表達式中具有一些特殊含義的字符
任意匹配元字符 .
邊界限制元字符 ^$
限定符 * ? + {n} {n,} {n,m}
模式匹配選擇
"python|c"

模式單元符
() 將一些原子組成一個大原子使用,小擴號里的部分會被當做一個整體去使用

3,模式修正
模式修正符,即可以在不改變正則表達式的情況下,通過模式修正符,改變正則表達式的含義,從而實現一些匹配結果的調整等功能,比如可以使用模式修正符I讓對於模式在匹配時不區分大小寫

4, 貪婪模式與懶惰模式
貪婪模式是盡可能的匹配
懶惰模式是盡可能的少匹配

示例:

# 正則表達式pattern1中,cd被看成一個大原子,此時的含義代表“cd”整體至少出現一次,當然會盡量多的匹配,所以此時,可以從源字符串"abcdcdcdcdfphp 345pythony_py"中匹配出結果'cdcdcdcd';
# 而在正則表達式pattern2中,其含義是d原子至少出現1次,而不會把cd看為一個整體,所以此時只能匹配到結果'cd'。
pattern1="(cd){1,}"
pattern2="cd{1,}"
string="abcdcdcdcdfphp345pythony_py"
result1=re.search(pattern1,string)
result2=re.search(pattern2,string)
print(result1)
print(result2)
<re.Match object; span=(2, 10), match='cdcdcdcd'>
<re.Match object; span=(2, 4), match='cd'>
result1.group(0)
'cdcdcdcd'
import re
pattern1="py.*n"
pattern2="cd{2}"
pattern3="cd{3}"
pattern4="cd{2,}"
string="abcdddfphp345pythony_py"
result1=re.search(pattern1,string)
result2=re.search(pattern2,string)
result3=re.search(pattern3,string)
result4=re.search(pattern4,string)
print(result1)
print(result2)
print(result3)
print(result4)
<re.Match object; span=(13, 19), match='python'>
<re.Match object; span=(2, 5), match='cdd'>
<re.Match object; span=(2, 6), match='cddd'>
<re.Match object; span=(2, 6), match='cddd'>
print(result2.group())
# 返回整個匹配對象
print(result2.groups())
#返回一個匹配所有子組的元組,如果沒有匹配成功,則返回一個空元組
cdd
()
import re
pattern1="(cd){1,}"
pattern2="cd{1,}"
string="abcdcdcdcdfphp345pythony_py"
result1=re.search(pattern1,string)
result2=re.search(pattern2,string)
print(result1)
print(result2)
<re.Match object; span=(2, 10), match='cdcdcdcd'>
<re.Match object; span=(2, 4), match='cd'>
result1.group()
'cdcdcdcd'
result2.group()
'cd'
result1.groups()
('cd',)
result2.groups()
()
import re
pattern1="python"
pattern2="python"
string="abcdfphp345Pythony_py"
result1=re.search(pattern1,string)
result2=re.search(pattern2,string,re.I)
print(result1)
print(result2)
None
<re.Match object; span=(11, 17), match='Python'>
# 貪婪模式與懶惰模式
import re
pattern1="p.*y"  #貪婪模式
pattern2="p.*?y" #懶惰模式
string="abcdfphp345pythony_py"
result1=re.search(pattern1,string)
result2=re.search(pattern2,string)
print(result1)
print(result2)
<re.Match object; span=(5, 21), match='php345pythony_py'>
<re.Match object; span=(5, 13), match='php345py'>
# 懶惰模式采用的是就近匹配原則,可以讓匹配結果更為精確,過貪婪模式匹配,已經找到了一個結尾y字符了,但仍然不會停止搜索,直到找不到結尾字符y為止才停止搜索,
# 用懶惰模式,一旦搜索到了結尾字符y,就立即停止
# 怎么設置貪婪模式和懶惰模式呢,通常情況下,如果我們想在某些字符間匹配任意字符,像“p.*y”這樣寫沒有任何的語法錯誤,這個時候默認是使用貪婪模式的
# 如果要轉化為懶惰模式,需要在對應的“.*”后面加上“?”,方可轉化為懶惰模式
##re.match()函數: 從頭開始匹配

import re
string="apythonhellomypythonhispythonourpythonend"
pattern=".python."
result=re.match(pattern,string)
result2=re.match(pattern,string).span()
# .span() 設置過濾不必需要的信息,只留下匹配成功的結果在源字符串中的位置
print(result)
print(result2)

<re.Match object; span=(0, 8), match='apythonh'>
(0, 8)
# re.search()函數會在全文中進行檢索並匹配
import re
string="hellomypythonhispythonourpythonend"
pattern=".python."
result=re.match(pattern,string)
result2=re.search(pattern,string)
print(result)
print(result2)
None
<re.Match object; span=(6, 14), match='ypythonh'>
# re.match() 和 re.search() 函數,即使原字符串中有多個結果符合模式,也只會匹配一個結果,如何將符合模式的內容全部匹配出來??
# 方式:
# 1,使用re.compile()對正則表達式預編譯
# 2,編譯后使用findall() 根據正則表達式從源字符串中將匹配的結果全部找出來
import re
string="hellomypythonhispythonourpythonend"
pattern=re.compile(".python.")#預編譯
result=pattern.findall(string)#找出符合模式的所有結果
print(result)
['ypythonh', 'spythono', 'rpythone']
## 或者
import re
string="hellomypythonhispythonourpythonend"
pattern=".python."
result=re.compile(pattern).findall(string)
print(result)
['ypythonh', 'spythono', 'rpythone']
## re.sub(pattern,rep,string,max)
# 第一個參數為對應的正則表達式,第二個參數為要替換成的字符串,第三個參數為源字符串,第四個參數為可選項,代表最多替換的次數,如果忽略不寫,則會將符合模式的結果全部替換
# re.sub()這個函數,會根據正則表達式pattern,從源字符串string查找出符合模式的結果,並替換為字符串rep,最多可替換max次。
import re
string="hellomypythonhispythonourpythonend"
pattern="python."
result1=re.sub(pattern,"php",string) #全部替換
result2=re.sub(pattern,"php",string,2) #最多替換兩次
print(result1)
print(result2)
hellomyphpisphpurphpnd
hellomyphpisphpurpythonend
## 匹配示例
# 匹配.com  .cn 后綴的url
import re
pattern="[a-zA-Z]+:// [^\s]*[.com|.cn]"
string="<a href='http:// www.baidu.com'>百度首頁</a>"
result=re.search(pattern,string)
print(result)


# 匹配電話號碼
import re
pattern="\d{4}-\d{7}|\d{3}-\d{8}" #匹配電話號碼的正則表達式
string="021-6728263653682382265236"
result=re.search(pattern,string)
print(result)

# 匹配郵件地址
import re
pattern="\w+([.+-]\w+)*@\w+([.-]\w+)*\.\w+([.-]\w+)*" #匹配電子郵件的正則表達式
string="<a href='http:// www.baidu.com'>百度首頁</a><br><a href='mailto:c-e+o@iqi-anyue.com.cn'>電子郵件地址</a>"
result=re.search(pattern,string)
print(result)

re.match()

嘗試從字符串的起始位置匹配一個模式,如果不是起始位置匹配的話,match()就會返回None
語法格式:
re.match(pattern,string,flags=0)

import re

content= "hello 123 4567 World_This is a regex Demo"
result = re.match('^hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$',content)
print(result)
print(result.group())
print(result.span())

result.group()獲取匹配的結果
result.span()獲去匹配字符串的長度范圍

泛匹配

import re

content= "hello 123 4567 World_This is a regex Demo"
result = re.match("^hello.*Demo$",content)
print(result)
print(result.group())
print(result.span())

匹配目標

如果為了匹配字符串中具體的目標,則需要通過()括起來

import re
content= "hello 1234567 World_This is a regex Demo"
result = re.match('^hello\s(\d+)\sWorld.*Demo$',content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())

通過re.group()獲得結果后,如果正則表達式中有括號,則re.group(1)獲取的就是第一個括號中匹配的結果

貪婪匹配

import re

content= "hello 1234567 World_This is a regex Demo"
result= re.match('^hello.*(\d+).*Demo',content)
print(result)
print(result.group(1))

只匹配到了7,並沒有匹配到1234567,出現這種情況的原因是前面的.* 給匹配掉了,.*在這里會盡可能的匹配多的內容,也就是我們所說的貪婪匹配.

#如果我們想要匹配到1234567則需要將正則表達式改為:

result= re.match('^he.*?(\d+).*Demo',content)

匹配模式

很多時候匹配的內容是存在換行的問題的,這個時候的就需要用到匹配模式re.S來匹配換行的內容

import re


content = """hello 123456 world_this
my name is zhaofan
"""

result =re.match('^he.*?(\d+).*?zhaofan$',content,re.S)
print(result)
print(result.group())
print(result.group(1))

轉義

import re

content= "price is $5.00"

result = re.match('price is \$5\.00',content)
print(result)
print(result.group())

對上面的一個小結:
盡量使用泛匹配,使用括號得到匹配目標,盡量使用非貪婪模式,有換行符就用re.S
強調re.match是從字符串的起始位置匹配一個模式

re.search

re.search掃描整個字符串返回第一個成功匹配的結果

import re

content = "extra things hello 123455 world_this is a Re Extra things"

result = re.search("hello.*?(\d+).*?Re",content)
print(result)
print(result.group())
print(result.group(1))

這個時候我們就不需要在寫^以及$,因為search是掃描整個字符串
注意:所以為了匹配方便,我們會更多的用search,不用match,match必須匹配頭部,所以很多時候不是特別方便


匹配練習

import re

html = '''<div id="songs-list">
    <h2 class="title">經典老歌</h2>
    <p class="introduction">
        經典老歌列表
    </p>
    <ul id="list" class="list-group">
        <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>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光輝歲月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陳慧琳">記事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="鄧麗君">但願人長久</a>
        </li>
    </ul>
</div>'''

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

re.findall

搜索字符串,以列表的形式返回全部能匹配的子串

import re

html = '''<div id="songs-list">
    <h2 class="title">經典老歌</h2>
    <p class="introduction">
        經典老歌列表
    </p>
    <ul id="list" class="list-group">
        <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>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光輝歲月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陳慧琳">記事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="鄧麗君">但願人長久</a>
        </li>
    </ul>
</div>'''

results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
print(results)
print(type(results))
for result in results:
    print(result)
    print(result[0], result[1], result[2])

例子2:

import re

html = '''<div id="songs-list">
    <h2 class="title">經典老歌</h2>
    <p class="introduction">
        經典老歌列表
    </p>
    <ul id="list" class="list-group">
        <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>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光輝歲月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陳慧琳">記事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="鄧麗君">但願人長久</a>
        </li>
    </ul>
</div>'''

results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>',html,re.S)
print(results)
for result in results:
    print(result[1])

總結:

\s*? 這種用法其實就是為了解決有的有換行,有的沒有換行的問題

(<a.*?>)? 這種用法是因為html中有的有a標簽,有的沒有的,?表示匹配一個或0個,正好可以用於匹配

re.sub re.subn

搜索和替換功能
subn()和 sub()一樣,但 subn()還返回一個表示替換的總數,替換后的字符串和表示替換總數的數字一起作為一個擁有兩個元素的元組返回。

import re

content = "Extra things hello 123455 World_this is a regex Demo extra things"

content = re.sub('\d+','',content)
print(content)

例子2:
在有些情況下我們替換字符的時候,還想獲取我們匹配的字符串,然后在后面添加一些內容

import re

content = "Extra things hello 123455 World_this is a regex Demo extra things"

content = re.sub('(\d+)',r'\1 7890',content)
print(content)

#\1是獲取第一個匹配的結果,為了防止轉義字符的問題,我們需要在前面加上r

split()分隔字符串


re.compile

將正則表達式編譯成正則表達式對象,方便復用該正則表達式

import re
content= """hello 12345 world_this
fan
"""

pattern =re.compile("hello.*fan",re.S)

result = re.match(pattern,content)
print(result)
print(result.group())

實驗:

import requests
import re
html = requests.get("http://www.iphai.com/free/wg")
find_tr = re.compile('<tr>(.*?)</tr>', re.S)
trs = find_tr.findall(html.text)  #需要獲取的是網頁的文本string   trs為列表
print(trs[2])  #出現不規則的一行
protocol = re.compile('<td>\s+HTTPS\s+</td>', re.S)
pp = protocol.findall(trs[3]) #匹配的是具有HTTPS的一行
['<td>\n                            HTTPS                        </td>']

protocol = re.compile('<td>\s+(HTTPS)\s+</td>', re.S)  #僅僅匹配分組,獲取分組
pp = protocol.findall(trs[3])  
print(pp)
['HTTPS']


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM