溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python正則表達(dá)式是什么,怎么用

發(fā)布時間:2021-06-25 11:42:33 來源:億速云 閱讀:164 作者:chen 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“Python正則表達(dá)式是什么,怎么用”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

一、re

我們先介紹一下re模塊下的方法,這個是我們拿來就可以用的,當(dāng)然前提是知道一點正則表達(dá)式,如果對正則表達(dá)式完全不了解,可以先看一下后面正則表達(dá)式部分。

1.1 match

match方法從字符串的起始位置匹配一個模式,如果沒有匹配成功match就返回None

re.match(pattern, string, flags=0)

pattern:正則表達(dá)式 string:待匹配的字符串 flags:匹配模式(是否區(qū)分大小寫、單行匹配還是多行匹配)

match返回的是一個re.Match對象,后面會詳細(xì)介紹Match中的方法。

import re

content = "Cats are smarter than dogs"

# 第一個參數(shù)是正則表達(dá)式,re.I表示忽略大小寫
match = re.match(r'(cats)', content, re.I)
print(type(match))
print(match.groups())

match = re.match(r'dogs', content, re.I)
print(type(match))
# print(match.groups())

match主要是用于捕獲分組,所以盡量使用分組模式,不然匹配了也無法獲取結(jié)果,flag是re.I表示忽略大小寫。

另外非常重要的一點match只會找第一個匹配的分組:

import re

content = "aa aa smarter aa dogs"

match = re.match(r'(aa)', content, re.I)
if match:
    print(match.groups())

上面輸出的是:('aa',)

1.2 search

掃描整個字符串并返回第一個成功的匹配,search和match不同之處在于,search沒有強制要求從開始匹配。

re.search(pattern, string, flags=0)
import re

content = '+123abc456*def789ghi'

# \w能夠匹配[a-zA-Z0-9_],+表示至少匹配一次
reg = r"\w+"
match = re.search(reg, content)

if match:
    print(match.group())

1.3 sub

替換字符串中的匹配項

re.sub(pattern, repl, string, count=0, flags=0)

pattern: 正則表達(dá)式 repl: 替換的字符串,可以是函數(shù) string: 要被查找替換的字符串 count: 模式匹配后替換的最大次數(shù),默認(rèn)0表示替換所有的匹配,可選 flags: 可選參數(shù),匹配模式,默認(rèn)為0

替換和諧字符:

import re

content = "do something fuck you"

rs = re.sub(r'fuck', "*", content)
print(rs)

非常簡單,把fuck替換為*

現(xiàn)在需求變了,我們需要被屏蔽的單詞有幾個字符,就替換為幾個*,怎么處理?

import re

def calcWords(matched):
    num = len(matched.group())
    return str(num * '*')

content = "do something fuck you"

rs = re.sub(r'fuck', calcWords, content)
print(rs)

替換的字符串可以使用函數(shù),我們在函數(shù)中就可以非常容易的計算了

1.4 findall

在字符串中找到正則表達(dá)式所匹配的所有子串,并返回一個列表,如果沒有找到匹配的,則返回空列表。

re.findall(pattern, string, flags=0)

pattern:正則表達(dá)式 string: 待匹配的字符串 flags: 可選參數(shù),匹配模式,默認(rèn)為0

import re

content = '+123abc456*def789ghi'

reg = r"\d+"
rs = re.findall(reg, content)
# ['123', '456', '789']
print(rs)

findall有一個讓人狂躁的地方是,如果正則表達(dá)式中有分組,就只會返回分組中的匹配。

import re

content = '+123abc456*def789ghi'

reg = r"\d+([a-z]+)"
rs = re.findall(reg, content)
# ['abc', 'ghi']
print(rs)

1.5 finditer

在字符串中找到正則表達(dá)式所匹配的所有子串,并把它們作為一個迭代器返回

re.finditer(pattern, string, flags=0)

pattern:正則表達(dá)式 string: 待匹配的字符串 flags: 可選參數(shù),匹配模式,默認(rèn)為0

import re

content = '+123abc456*def789ghi'

reg = r"\d+"
rss = re.finditer(reg, content)

# 123 456 789 
for rs in rss:
    print(rs.group(), end=' ')

finditer和findall差不多,但是沒有findall的那個令人狂躁的如果有分組只返回分組的問題。

import re

content = '+123abc456*def789ghi'

reg = r"\d+([a-z]+)"
rss = re.finditer(reg, content)

# 123abc 789ghi
for rs in rss:
    print(rs.group(), end=' ')

1.6 split

按照匹配的子串將字符串分割后返回列表

re.split(pattern, string, maxsplit=0, flags=0)
import re

content = '+123abc456*def789ghi'

reg = r"\d+"
rs = re.split(reg, content)

print(rs)

1.7 compile

編譯正則表達(dá)式,生成一個正則表達(dá)式Pattern對象,前面的方法都會先調(diào)用這個方法得到一個Pattern對象,然后再使用Pattern對象的同名方法。

接下來,我們馬上就會介紹一下Pattern對象。

re.compile(pattern, flags=0)

二、Pattern

Pattern對象是一個編譯好的正則表達(dá)式,Pattern不能直接實例化,必須使用re.compile()進(jìn)行構(gòu)造。

2.1 屬性

屬性說明
pattern編譯使用的正則表達(dá)式
flags編譯時用的匹配模式,數(shù)字形式
groups表達(dá)式中分組的數(shù)量
groupindex字典,鍵是分組的別名,值是分組的編號
import re

pattern = re.compile(r'(\w+)(?P<gname>.*)', re.S)

# pattern: (\w+)(?P<gname>.*)
print("pattern:", pattern.pattern)
# flags: 48
print("flags:", pattern.flags)
# groups: 2
print("groups:", pattern.groups)
# groupindex: {'gname': 2}
print("groupindex:", pattern.groupindex)

2.2 方法

前面re模塊中介紹的方法對于Pattern都適用,只是少了pattern參數(shù)

其實很簡單,re模塊中的方法使用pattern參數(shù),通過re.compile方法構(gòu)造了一個Pattern對象

三、Match

Match對象是一次匹配的結(jié)果,包含此次匹配的信息,可以使用Match提供的屬性或方法來獲取這些信息。

3.1 屬性

屬性說明
string匹配時使用的文本
re獲取Pattern的表達(dá)式
pos文本中正則表達(dá)式開始搜索的位置
endpos文本中正則表達(dá)式結(jié)束搜索的位置
lastindex最后一個被捕獲的分組在文本中的索引。如果沒有被捕獲的分組,將為None
lastgroup最后一個被捕獲的分組的別名。如果沒有被捕獲的分組,將為None
import re

content = "123456<H1>first</h2>123456"

reg = r'\d+<[hH](?P<num>[1-6])>.*?</[hH](?P=num)>'

match = re.match(reg, content)

# string: 123456<H1>first</h2>123456
print("string:", match.string)
# re: re.compile('\\d+<[hH](?P<num>[1-6])>.*?</[hH](?P=num)>')
print("re:", match.re)
# pos: 0
print("pos:", match.pos)
# endpos: 26
print("endpos:", match.endpos)
# lastindex: 1
print("lastindex:", match.lastindex)
# lastgroup: num
print("lastgroup:", match.lastgroup)

感覺Match的屬性稍微有些雞肋。

3.2 方法

方法說明
groups()獲取所有分組匹配的字符串,返回元組
group([group1,……])獲取分組匹配到的字符串,返回元組
start(group)獲取分組在原始字符串中的開始匹配位置
end(group)獲取分組在原始字符串中的結(jié)束匹配位置
span(group)獲取分組在原始字符串中的開始和結(jié)束匹配位置,元組
groupdict()獲取有別名的分組匹配的字符串,返回字典,別名是鍵
expand(template)template字符串中可以通過別名和編號引用匹配字符串

注意:無參數(shù)group等價于group(0),返回整個匹配到的字符串

import re

match = re.match(r'(\w+) (\w+) (?P<name>.*)', 'You love sun')

# groups(): ('You', 'love', 'sun')
print("groups():", match.groups())
# group(2,3): ('love', 'sun')
print("group(2,3):", match.group(2, 3))
# start(2): 4
print("start(2):", match.start(2))
# end(2): 8
print("end(2):", match.end(2))
# span(2): (4, 8)
print("span(2):", match.span(2))
# groupdict(): {'name': 'sun'}
print("groupdict():", match.groupdict())
# expand(r'I \2 \1!'): I love You!
print(r"expand(r'I \2 \1!'):", match.expand(r'I \2 \1!'))

上面Match中的方法還是比較重要的,因為我們基本最后都是通過Match對象中的方法來獲取匹配的

四、正則表達(dá)式

4.1 常用

表達(dá)式說明
.匹配任意字符,除了換行符,當(dāng)re.S標(biāo)記被指定時,則可以匹配包括換行符的任意字符
?匹配0個或1個由前面的正則表達(dá)式定義的片段,非貪婪方式
+匹配1個或多個的表達(dá)式
*匹配0個或多個的表達(dá)式
[]用來表示一組字符,單獨列出,[abc] 匹配 'a'、'b'或'c'
[^]不在[]中的字符,[^abc] 匹配除了a,b,c之外的字符
^匹配字符串開頭,多行模式也匹配行結(jié)尾
\A匹配字符串開頭
$匹配字符串末尾,多行模式也匹配行結(jié)尾
\Z匹配字符串末尾
{n}精確n個,"o{2}"匹配food,不匹配fod、foood
{n,}至少n個,"o{2,}"匹配food,foood,不匹配fod
{n, m}匹配n到m,"o{2,3}",匹配food,foood,不匹配fod、fooood
|a|b,匹配a或b
--可以表示區(qū)間,[0-9]表示可以匹配0-9中的任意數(shù)字

最常用的就是.匹配任意字符,a.b就可以匹配abb、acb、adb、a+b、a8b等等

?表示最多匹配一次:abb?可以匹配ab、abb,但是不能匹配abbabb,因為?只是指前一個片段

+表示至少匹配一次:abb+可以匹配abb、abbb、abbbb等等,當(dāng)時不能匹配ab

*表示0到多次: abb*可以匹配ab、abb、abbb、abbbb等等

[]中有一組字符,字符間的關(guān)系是或

Python正則表達(dá)式是什么,怎么用

4.2 邊界空白

表達(dá)式說明
\t制表符
\n換行
\r回車
\f換頁
\w匹配數(shù)字、字母、下劃線,等價于[a-zA-Z0-9_]
\W匹配非(數(shù)字、字母、下劃線),等價于[^a-zA-Z0-9_]
\s匹配空白字符,等價于[\t\n\r\f]
\S匹配非空字符,等價于[^\t\n\r\f]
\d匹配數(shù)字,等價于[0-9]
\D匹配非數(shù)字,等價于[^0-9]
\b匹配單詞邊界,'er\b' 可以匹配"over"中的'er',但不能匹配"service"中的'er'
\B匹配非單詞邊界,'er\B'能匹配"service"中的'er',但不能匹配"over"中的'er'

Python正則表達(dá)式是什么,怎么用

4.3 分組

表達(dá)式說明
(re)分組匹配,嵌套模式分組計數(shù)是從左到右,從外到里
\number引用分組,使用\1、\2、\3……訪問第1、2、3……分組
(?P<name>)指定分組名稱,使用name做為分組的別名
(?P=name)引用分組名稱,通過name應(yīng)用分組

Python正則表達(dá)式是什么,怎么用

分組最重要的一個作用就是可以回溯,就是引用已經(jīng)匹配的模式。

思考:html中如何匹配全部h標(biāo)簽?

reg = '<[hH][1-6]>.*?</[hH][1-6]>'

很多朋友可能會寫出類似于上面的表達(dá)式,有什么問題嗎?

看下面的例子:

import re

content = '''
    <html>
    <body>
      <H1>first</h2>
      <p>p tag</p>
      <h3>h3</h3>
      <h4>非法標(biāo)簽</h5>
    </body>
    </html>
'''

rs = re.findall(r'<[hH][1-6]>.*?</[hH][1-6]>', content)
print(rs)

rs = re.findall(r'<[hH]([1-6])>.*?</[hH]\1>', content)
print(rs)

rs = re.findall(r'((<[hH]([1-6])>).*?</[hH]\3>)', content)
print(rs)

rs = re.findall(r'((<[hH](?P<num>[1-6])>).*?</[hH](?P=num)>)', content)
print(rs)

看輸出,我們知道:

reg = '<[hH][1-6]>.*?</[hH][1-6]>'

會把'<h4>非法標(biāo)簽</h5>'這一部分也匹配到。

我們可以通過分組,然后引用分組來解決這個問題。

reg1 = '<[hH]([1-6])>.*?</[hH]\1>'
reg2 = '((<[hH]([1-6])>).*?</[hH]\3>)'

因為如果有分組,findall之后打印出匹配分組,所以我們使用reg2這個正則表達(dá)式。

為什么是\3呢?

因為根據(jù)從左到右,從外到里的原則,我們知道([1-6])是第3個分組。

如果覺得不想去數(shù),或者怕數(shù)錯,那么就可以使用別名的方式。

reg = '((<[hH](?P<num>[1-6])>).*?</[hH](?P=num)>)'

4.4 前后匹配

表達(dá)式說明
(?=re)前向匹配,a(?=\d),匹配數(shù)字前面的a
(?!re)前向反向匹配,a(?!\d),匹配后面不接數(shù)字的a
(?<=re)向后匹配,(?<=\d)a,匹配前面是數(shù)字的a
(?< !re)向后反向匹配,(?< !\d)a,匹配前面不是數(shù)字的a

前后匹配也是一個非要有用的功能,它的一個重要特性是不消費re部分,下面看一個例子幫助理解。

import re

content = '''
http://www.mycollege.vip
https://mail.mycollege.vip
ftp://ftp.mycollege.vip
'''

# 向前匹配,匹配:前面的schema,不消費:
rs = re.findall(r'.+(?=:)', content)
# ['http', 'https', 'ftp']
print(rs)

# 向后匹配,匹配//后面的域名,不消費//
rs = re.findall(r'(?<=//).+', content)
# ['www.mycollege.vip', 'mail.mycollege.vip', 'ftp.mycollege.vip']
print(rs)

# 向后匹配,匹配$后面的數(shù)字,不消費$
price = '''
item1:$99.9
CX99:$199
ZZ88:$999
'''

rs = re.findall(r'(?<=\$)[0-9.]+', price)
# ['99.9', '199', '999']
print(rs)

# 前后匹配
title = '''
<head>
    <title>this is title</title>
</head>
'''

rs = re.findall(r'(?<=<title>).*(?=</title>)', title)
# ['this is title']
print(rs)

4.5 其他匹配

表達(dá)式說明
(?:re)(re)的不分組版本,(?:abc){2},匹配abcabc
(?imsuxL:re)在括號中使用imsuxL對應(yīng)flag中的大寫,(?i:abc),匹配ABC
(?-imsuxL:re)在括號中不使用imsuxL對應(yīng)flag中的大寫
(?#...)#后面的內(nèi)容為注釋忽略

Python正則表達(dá)式是什么,怎么用

4.6 flags

模式說明
re.IIGNORECASE,使匹配對大小寫不敏感
re.MMULTILINE,多行匹配,影響^和$
re.SDOTALL,點任意匹配模式,使.匹配包括換行在內(nèi)的所有字符
re.XVERBOSE,詳細(xì)模式,忽略表達(dá)式中的空白和注釋,并允許使用#添加注釋
re.LLOCALE
re.UUNICODE

Python正則表達(dá)式是什么,怎么用

re.M是多行匹配模式:

  1. ^可以匹配字符串開頭,也可以匹配行的開頭,字符串中換行符\n之后的位置

  2. $可以匹配字符串結(jié)尾,也可以匹配行的結(jié)尾,字符串中換行符\n之前的位置

單行模式:

  1. ^等價于\A

  2. $等價于\Z

import re

content = '''
first line
second line
third line
'''

# ['first', 'second', 'third']
rs = re.findall(r'^(.*) line$', content, re.M)
# []
# rs = re.findall(r'^(.*) line$', content)
# []
# rs = re.findall(r'\A(.*) line\Z', content, re.M)
print(rs)

上面的小例子多行模式可以匹配成功,單行模式不能,因為單行模式^不能匹配\n后的位置,所以開頭就不匹配。

反過來,我們在決定是否使用re.M的時候,只需要考慮正則表達(dá)式中有沒有^和$,如果沒有肯定是不需要的,如果有,那么思考是否需要匹配\n(換行符)前后的位置,需要則加上re.M。

re.L和re.U比較不好理解,2.x和3.x的變化也很大,基本用不上,有興趣可以看一下文檔。

“Python正則表達(dá)式是什么,怎么用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI