Python 正則表達式基礎知識點及實例

1. 什麼是正則表達式

正則表達式(Regular Expressions),也稱為 “regex” 或 “regexp” 是使用單個字符串來描述、匹配一系列匹配某個句法規則的字符串,這樣程序就可以將該模式與任意文本字符串相匹配。

使用正則表達式,可以為要匹配的可能字符串集指定規則;此集可能包含英語句子,電子郵件地址,TeX命令或你喜歡的任何內容

正則表達式引擎

采用不同算法,檢查處理正則表達式的軟件模塊 PCRE (perl compatible regular expressions)

正則表達式的元字符分類: 字符匹配,匹配次數,位置錨定,分組

Python的正則表達式是PCRE標準的。

2. 正則表達式基礎

# 字符匹配

. 匹配任意單個字符(換行符除外)

[]匹配指定范圍內的任意單個字符: [0-9] [a-z]

^[xxx]以[]內的任意字符開頭

[^xxx]: 除瞭[]內的字符,相當於取反

# 匹配次數

用於指定前面的字符要出現幾次

* 匹配前面的字符的任意次,包括0次, 貪婪匹配:盡可能長的匹配
.* 任意長度的任意字符
? 匹配其前面的字符0或1次
+ 匹配前面的字符至少1次
{n} 匹配前面的字符n次
{m,n} 匹配前面的字符至少m次,最多n次如{1,3} 匹配1到3次
{n,} 匹配前面的字符至少n次

# 位置錨定
# 用於定位出現的位置

^ 行首

$ 行尾

^$ 空行

# 分組
() 分組,用()將多個字符捆綁在一起,當作一個整體處理
後向引用: \1,\2

# | 或者
a|b a 或 b
(A|a)bc Abc或abc

# \ 轉義
\ 反斜杠後面可以跟各種字符,以指示各種特殊序列。它也用於轉義所有元字符.因此您仍然可以在模式中匹配它們,如果你需要匹配 [ 或 \,你可以在它們前面加一個反斜杠來移除它們的特殊含義:\[ 或 \\。
在python中取消轉義推薦使用r,如果要匹配’\n’,因為’\n’有特殊含義:回車。要匹配’\n’可以以寫’\\n’,在Python中可以使用r’\n’。

\d 匹配任何十進制數,等價於類 [0-9]
\w 匹配任何字母與數字字符包括下劃線;這相當於類 [a-zA-Z0-9_]。
\s 匹配任何空白字符;這等價於類 [ \t\n\r\f\v]。

\D 匹配任何非數字字符;這等價於類 [^0-9]。
\W 匹配任何非字母與數字字符;這相當於類 [^a-zA-Z0-9_]。
\S 匹配任何非空白字符;這相當於類 [^ \t\n\r\f\v]。

3. Python中使用正則表達式

在python中使用正則表達式常用的模塊為:re。

3.1 re常用的方法

# re.findall('正則表達式','待匹配的文本')  根據正則匹配出所有符合條件的數據,返回列表
>>> re.findall('[0-9]', "Hello world 123")
['1', '2', '3']
# 如果匹配不到findall返回一個空列表

# re.finditer('正則表達式','待匹配的文本') 根據正則匹配出所有符合條件的數據,返回一個對象
>>> re.finditer('[0-9]', "Hello world 123")     
<callable_iterator object at 0x7f3409296d68>
# 取值:
>>> res = re.finditer('[0-9]', "Hello world 123")
>>> for i in res:
...     print(i.group())
... 
1
2
3

# 如果匹配不到finditer返回空。

# findall 和finditer功能一樣,但是finditer更節省內存。

# re.search('正則表達式','待匹配的文本')   根據正則匹配到一個符合條件的就結束
>>> res = re.search('l', "Hello world 123")     
>>> res
<_sre.SRE_Match object; span=(2, 3), match='l'>
>>> res.group()
'l'
# 匹配到一個就返回,group()返回具體的元素,如果匹配不到search返回None,使用group取值就會報錯:
AttributeError: 'NoneType' object has no attribute 'goup'
    
# re.match('正則表達式','待匹配的文本') 根據正則從頭開始匹配(文本內容必須在開頭匹配上)
>>> res = re.match('e', "Hello world 123")   # e 不在開頭,所以匹配不上,返回None
>>> print(res)
None

>>> res = re.match('H', "Hello world 123")  # H 為開頭能匹配上
>>> print(res)
<_sre.SRE_Match object; span=(0, 1), match='H'>
>>> print(res.group())
H

#如果沒有匹配到,match會返回None 使用group取值的時候也會直接報錯
AttributeError: 'NoneType' object has no attribute 'group'


# search和match匹配不到都會報錯,可以處理一下:
if res:
    print(res.group())
else:
    print('沒有匹配到')
    
# re.split 分割
>>> re.split('[0-9]', "Hello 123 world")    # 按匹配到的分割,返回一個列表   
['Hello ', '', '', ' world'] 

# re.sub('要匹配的', '要替換的', '文本')  替換
>>> re.sub('[0-9]','A', "Hello 123 world")  # 默認替換全部
'Hello AAA world'
>>> re.sub('[0-9]','A', "Hello 123 world",1) # 替換一次
'Hello A23 world'
>>> re.sub('[0-9]','A', "Hello 123 world",2) # 替換兩次
'Hello AA3 world'
# re.subn() 和re.sub 功能一樣,但是返回元組 並提示替換瞭幾處
>>> re.subn('[0-9]','A', "Hello 123 world")    
('Hello AAA world', 3)
>>> re.subn('[0-9]','A', "Hello 123 world", 1)
('Hello A23 world', 1)

# 如果一個正則表達式在程序中經常用到,這樣每次都寫太麻煩,可以使用compile將正則表達式的樣式編譯為一個正則表達式對象 (正則對象)
# 例如 正則表達式'^\d{3,6}'經常使用
>>> obj = re.compile('^\d{3,6}')
>>> obj.findall("123 Hello")
['123']
>>> res = obj.search("123 Hello")
>>> res.group()
'123'
# obj還可以使用 finditer,match,split,subn,sub

# 分組
>>> res = re.search('[1-9]\d{16}([0-9x])','37152119841105155x')   
>>> res.group()
'37152119841105155x'
>>> res.group(1)  # 隻打印分組1裡的內容,1為第一個分組,這裡面隻有([0-9x])所以打印x
'x'
>>> res = re.search('[1-9](\d{16})([0-9x])','37152119841105155x')
>>> res.group() 
'37152119841105155x'
>>> res.group(1)   # (\d{16}) 為第1個分組
'7152119841105155'
>>> res.group(2)	# ([0-9x]) 為第2個分組
'x'
# 這種取分組裡的值也為索引取值

# findall優先打印出分組裡的內容
>>> re.findall('[1-9]\d{16}([0-9x])','37152119841105155x')
['x']

# 取消分組: ?:
>>> res = re.findall('[1-9]\d{16}(?:[0-9x])','37152119841105155x')  
>>> res   # (?:[0-9x])
['37152119841105155x']

# 上面的分組為無名分組,分組也可以有名字。
# 有名分組  ?P<分組名稱>
>>> res = re.search('[1-9](?P<first>\d{16})(?P<second>[0-9x])','37152119841105155x')
>>> res.group()
'37152119841105155x'
>>> res.group('first')
'7152119841105155'
>>> res.group('second')
'x'
# 分組後也可以使用索引到值:
>>> res.group(2)       
'x'

3.2 re模塊練習

爬鏈傢二手房前十頁

import re
import requests 

for i in range(1,11):

    url = 'https://bj.lianjia.com/ershoufang/pg{}srs%E6%97%A7%E5%AE%AB/'.format(i)

    r = requests.get(url)

    title = re.findall('data-is_focus="" data-sl="">(.*?)</a>',r.text)
    price = re.findall('<span>([0-9]{3})</span>',r.text)

    address = re.findall('data-log_index="\d" data-el="region">(.*?)</a>', r.text)
    houseIcon = re.findall('<span class="houseIcon"></span>(.*?)</div>', r.text)



    res = zip(title,price,address,houseIcon)
    for i in res:
    # print("%s \t%s(萬) \t%s\t%s" % (i[0], i[1], i[2], i[3])) 
        print("""
    小區名: %s,
    總價: %s萬,
    地址: %s,
    房型: %s""" % (i[0], i[1], i[2], i[3]))
    
# 執行結果:
[root@hans_tencent_centos82 module]# python3 houses.py 

    小區名: 紅星樓小區 南北通透一居室 滿五唯一商品房,
    總價: 185萬,
    地址: 紅星樓 ,
    房型: 1室1廳 | 46.46平米 | 南 北 | 簡裝 | 頂層(共6層) | 1989年建 | 板樓

    小區名: 舊宮北裡 2室2廳 南 北,
    總價: 469萬,
    地址: 舊宮北裡 ,
    房型: 2室2廳 | 96.55平米 | 南 北 | 精裝 | 高樓層(共9層) | 2004年建 | 板樓

    小區名: 亦莊北岸 3室1廳 南 北,
    總價: 558萬,
    地址: 亦莊北岸 ,
    房型: 3室1廳 | 109.58平米 | 南 北 | 精裝 | 中樓層(共15層) | 2008年建 | 板塔結合

參考內容:

Python官方文檔

內容擴展:

Python對正則表達式的支持

Python提供瞭re模塊來支持正則表達式相關操作,下面是re模塊中的核心函數。

函數 說明
compile(pattern, flags=0) 編譯正則表達式返回正則表達式對象
match(pattern, string, flags=0) 用正則表達式匹配字符串 成功返回匹配對象 否則返回None
search(pattern, string, flags=0) 搜索字符串中第一次出現正則表達式的模式 成功返回匹配對象 否則返回None
split(pattern, string, maxsplit=0, flags=0) 用正則表達式指定的模式分隔符拆分字符串 返回列表
sub(pattern, repl, string, count=0, flags=0) 用指定的字符串替換原字符串中與正則表達式匹配的模式 可以用count指定替換的次數
fullmatch(pattern, string, flags=0) match函數的完全匹配(從字符串開頭到結尾)版本
findall(pattern, string, flags=0) 查找字符串所有與正則表達式匹配的模式 返回字符串的列表
finditer(pattern, string, flags=0) 查找字符串所有與正則表達式匹配的模式 返回一個迭代器
purge() 清除隱式編譯的正則表達式的緩存
re.I / re.IGNORECASE 忽略大小寫匹配標記
re.M / re.MULTILINE 多行匹配標記

說明: 上面提到的re模塊中的這些函數,實際開發中也可以用正則表達式對象的方法替代對這些函數的使用,如果一個正則表達式需要重復的使用,那麼先通過compile函數編譯正則表達式並創建出正則表達式對象無疑是更為明智的選擇。

到此這篇關於Python 正則表達式基礎知識點及實例的文章就介紹到這瞭,更多相關Python 正則表達式 淺析內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: