09.正則表達式re-1.正則表達式

1、正則表達式概述

正則表達式(英語:Regular Expression,在代碼中常簡寫為regex、regexp或RE),是計算機科學的一個概念。
正則表達式使用單個字符串來描述、匹配一系列匹配某個句法規(guī)則的字符串。
在很多文本編輯器里,正則表達式通常被用來檢索、替換那些匹配某個模式的文本。

2、re模塊

2.1re 模塊

使 Python語言擁有全部的正則表達式功能。
re 模塊提供了一些函數(shù),這些函數(shù)使用一個模式字符串做為它們的第一個參數(shù),用于正則表達式匹配和替換。

2.2re模塊的使用

  • re.match 函數(shù)

re.match 嘗試從字符串的起始位置匹配一個模式,若字符串起始位置匹配正則表達式,則match方法返回匹配對象(Match Object),如果不是起始位置匹配成功的話,match()就返回none(注意不是“空字符串”)。

  • 語法:

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

  • 參數(shù):
pattern – 匹配的正則表達式 

string – 要匹配的字符串。 

flags – 標志位,用于控制正則表達式的匹配方式,如:是否區(qū)分大小寫,多行匹配等等。

匹配對象Macth Object具有g(shù)roup方法,我們可以使用group(num) 或 groups() 匹配對象函數(shù)來獲取匹配表達式。

group(num=0) 
匹配的整個表達式的字符串,group() 可以一次輸入多個組號,在這種情況下它將返回一個包含那些組所對應值的元組。 

groups() 
返回一個包含所有小組字符串的元組,從 1 到 所含的小組號。
示例1:

# 導入re模塊
import re

# 使用match方法進行匹配操作
result = re.match(正則表達式,要匹配的字符串)

# 如果上一步匹配到數(shù)據(jù)的話,可以使用group方法來提取數(shù)據(jù)
result.group()
示例2:

import re

ret = re.match("taobao","taobao.com")
print(ret)
print(ret.group())

運行結(jié)果:

<_sre.SRE_Match object; span=(0, 6), match='taobao'>
taobao

3、表示字符

正則表達式的單字符匹配:

字體 功能
. 匹配任意一個字符(除了\n)
[] 匹配[]中列舉的字符
\d 匹配數(shù)字,即0-9
\D 匹配非數(shù)字,即不是數(shù)字
\s 匹配空白,即 空格,tab鍵
\S 匹配非空白
\w ==匹配包括下劃線的任何單詞字符。類似但不等價于“[A-Za-z0-9_]”,這里的"單詞"字符使用Unicode字符集。==
\W 匹配非單詞字符

匹配中文字符的正則表達式: [\u4e00-\u9fa5]

  • 示例1:‘.’

匹配任意字符,除了換行符,當re.DOTALL標記被指定時,則可以匹配包括換行符的任意字符。

ret = re.match('.','a')
print(ret.group())

ret = re.match('.','A')
print(ret.group())

ret = re.match('.',' ')
print(ret.group())

ret = re.match('.','\nab')
print(ret.group())     錯誤

ret = re.match('..','\rab')
print(ret.group())

ret = re.match('..','\tab')
print(ret.group())

ret = re.match('.','好好學習')
print(ret.group())

ret = re.match('....','好好學習')
print(ret.group())
  • 示例2:’[ ]‘

用來表示一組字符,單獨列出:[amk] 匹配 ‘a(chǎn)’,’m’或’k’

ret = re.match('[Hh]','hello')
print(ret.group())

ret = re.match('[Hh]','Hello')
print(ret.group())

ret = re.match('[A-Z]','Hello')
print(ret.group())

ret = re.match('[0-9a-z]','00')
print(ret.group())

ret = re.match('[0-9a-z]','aa')
print(ret.group())

ret = re.match('[\u4e00-\u9fa5]*','陳佳睿')
print(ret)
print(ret.group())
  • 示例3:’\d, \D, \s, \S‘

\d – 匹配一個數(shù)字字符。等價于 [0-9]。

\D –匹配一個非數(shù)字字符。等價于 [^0-9]。

\s –匹配任何空白字符,包括空格、制表符、換頁符等等。等價于 [ \f\n\r\t\v]。

\S –匹配任何非空白字符。等價于 [^ \f\n\r\t\v]。

ret = re.match('小米\d','小米6')
print(ret.group())

ret = re.match('小\D\d','小米6')
print(ret.group())

ret = re.match('\s',' 小米')
print(ret)

ret = re.match('\s','\nab')
print(ret)

ret = re.match('\S','小米')
print(ret)

ret = re.match('\S','0123')
print(ret)

ret = re.match('\S\S\S','x米6')
print(ret)


運行結(jié)果:
小米6
小米6
<_sre.SRE_Match object; span=(0, 1), match=' '>
<_sre.SRE_Match object; span=(0, 1), match='\n'>
<_sre.SRE_Match object; span=(0, 1), match='小'>
<_sre.SRE_Match object; span=(0, 1), match='0'>
<_sre.SRE_Match object; span=(0, 3), match='x米6'>
  • 示例4:’\w, \W‘

\w ==匹配包括下劃線的任何單詞字符。類似但不等價于“[A-Za-z0-9_]”,這里的"單詞"字符使用Unicode字符集。==。

\W 匹配任何非單詞字符。等價于 ‘[^A-Za-z0-9_]’。

ret = re.match('\w','hello')
print(ret)

ret = re.match('\w\w','_hello')
print(ret)

ret = re.match('\w','陳')
print(ret)

ret = re.match('\W\W\w','。.Hello')
print(ret)

ret = re.match('\W','陳hello')
print(ret)  #None

ret = re.match('\W','陳hello',re.ASCII) #匹配各個國家文字
print(ret)  #<_sre.SRE_Match object; span=(0, 1), match='陳'>\

ret = re.match('[\u4e00-\u9fa5]','哈hello')
print(ret)

運行結(jié)果:
<_sre.SRE_Match object; span=(0, 1), match='h'>
<_sre.SRE_Match object; span=(0, 2), match='_h'>
<_sre.SRE_Match object; span=(0, 1), match='陳'>
<_sre.SRE_Match object; span=(0, 3), match='。.H'>
None
<_sre.SRE_Match object; span=(0, 1), match='陳'>
<_sre.SRE_Match object; span=(0, 1), match='哈'>

4、原始字符串

>>> mm = "c:\\a\\b\\c"
>>> mm
'c:\\a\\b\\c'
>>> print(mm)
c:\a\b\c
>>> print(mm)
c:\a\b\c
>>> re.match("c:\\\\",mm).group()
'c:\\'
>>> ret = re.match("c:\\\\",mm).group()
>>> print(ret)
c:\
>>> ret = re.match("c:\\\\a",mm).group()
>>> print(ret)
c:\a
>>> ret = re.match(r"c:\\a",mm).group()
>>> print(ret)
c:\a
>>> ret = re.match(r"c:\a",mm).group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'

python中字符串前面加上 r 表示原生字符串

與大多數(shù)編程語言相同,正則表達式里使用”\”作為轉(zhuǎn)義字符,這就可能造成反斜杠困擾。假如你需要匹配文本中的字符”\”,那么使用編程語言表示的正則表達式里將需要4個反斜杠”\”:前兩個和后兩個分別用于在編程語言里轉(zhuǎn)義成反斜杠,轉(zhuǎn)換成兩個反斜杠后再在正則表達式里轉(zhuǎn)義成一個反斜杠。

Python里的原生字符串很好地解決了這個問題,有了原始字符串,你再也不用擔心是不是漏寫了反斜杠,寫出來的表達式也更直觀。

>>> ret = re.match(r"c:\\a",mm).group()
>>> print(ret)
c:\a

5、表示數(shù)量

匹配多個字符的相關(guān)格式

字符 功能
* 匹配前一個字符出現(xiàn)0次或者無限次,即可有可無
+ 匹配前一個字符出現(xiàn)1次或者無限次,即至少有1次
? 匹配前一個字符出現(xiàn)1次或者0次,即要么有1次,要么沒有
{m} 匹配前一個字符出現(xiàn)m次
{m,} 匹配前一個字符至少出現(xiàn)m次
{m,n} 匹配前一個字符出現(xiàn)從m到n次

6、表示邊界

字符 功能
^ 匹配字符串開頭
$ 匹配字符串結(jié)尾
\b 匹配一個單詞的邊界
\B 匹配非單詞邊界
  • 示例1:$

需求:匹配163.com的郵箱地址

import re

# 正確的地址
ret = re.match("[\w]{4,20}@163\.com", "xiaoWang@163.com")
ret.group()

# 不正確的地址
ret = re.match("[\w]{4,20}@163\.com", "xiaoWang@163.comheihei")
ret.group()

# 通過$來確定末尾
ret = re.match("[\w]{4,20}@163\.com$", "xiaoWang@163.comheihei")
ret.group()
  • 示例2: \b
>>> re.match(r".*\bver\b", "ho ver abc").group()
'ho ver'

>>> re.match(r".*\bver\b", "ho verabc").group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'

>>> re.match(r".*\bver\b", "hover abc").group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
  • 示例3:\B
>>> re.match(r".*\Bver\B", "hoverabc").group()
'hover'

>>> re.match(r".*\Bver\B", "ho verabc").group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'

>>> re.match(r".*\Bver\B", "hover abc").group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'

>>> re.match(r".*\Bver\B", "ho ver abc").group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'

7、匹配分組

字符 功能
匹配左右任意一個表達式
(ab) 將括號中字符作為一個分組
\num 引用分組num匹配到的字符串
(?P<name>) 分別起組名
(?P=name) 引用別名為name分組匹配到字符串
  • 示例1:|

需求:匹配出0-100之間的數(shù)字

import re

ret = re.match("[1-9]?\d","8")
print(ret)

ret = re.match("[1-9]?\d","78")
print(ret)

# 不能正常匹配到的情況
ret = re.match("[1-9]?\d","08")
print(ret)

# 修正之后的
ret = re.match("[1-9]?\d$","8")
print(ret)

# 添加|
ret = re.match("[1-9]?\d$|100","8")
print(ret)

ret = re.match("[1-9]?\d$|100","78")
print(ret)

ret = re.match("[1-9]?\d$|100","8")
print(ret)

ret = re.match("[1-9]?\d$|100","100")
print(ret)

運行結(jié)果:
<_sre.SRE_Match object; span=(0, 1), match='8'>
<_sre.SRE_Match object; span=(0, 2), match='78'>
<_sre.SRE_Match object; span=(0, 1), match='0'>
<_sre.SRE_Match object; span=(0, 1), match='8'>
<_sre.SRE_Match object; span=(0, 1), match='8'>
<_sre.SRE_Match object; span=(0, 2), match='78'>
<_sre.SRE_Match object; span=(0, 1), match='8'>
<_sre.SRE_Match object; span=(0, 3), match='100'>
  • 示例2:( )

需求:匹配出163、126、qq郵箱之間的數(shù)字

import re

ret = re.match("\w{4,20}@163\.com", "test@163.com")
ret.group()

ret = re.match("\w{4,20}@(163|126|qq)\.com", "test@126.com")
ret.group()

ret = re.match("\w{4,20}@(163|126|qq)\.com", "test@qq.com")
ret.group()

ret = re.match("\w{4,20}@(163|126|qq)\.com", "test@gmail.com")
ret.group()
>>> ret = re.match("([^-]*)-(\d+)","010-12345678")
>>> ret.group()
'010-12345678'
>>> ret.group(1)
'010'
>>> ret.group(2)
'12345678'
  • 示例3:\

需求:匹配出<html>hh</html>

import re

# 能夠完成對正確的字符串的匹配
ret = re.match("<[a-zA-Z]*>\w*</[a-zA-Z]*>", "<html>hh</html>")
ret.group()

# 如果遇到非正常的html格式字符串,匹配出錯
ret = re.match("<[a-zA-Z]*>\w*</[a-zA-Z]*>", "<html>hh</htmlbalabala>")
ret.group()

# 正確的理解思路:如果在第一對<>中是什么,按理說在后面的那對<>中就應該是什么

# 通過引用分組中匹配到的數(shù)據(jù)即可,但是要注意是元字符串,即類似 r""這種格式
ret = re.match(r"<([a-zA-Z]*)>\w*</\1>", "<html>hh</html>")
ret.group()

# 因為2對<>中的數(shù)據(jù)不一致,所以沒有匹配出來
ret = re.match(r"<([a-zA-Z]*)>\w*</\1>", "<html>hh</htmlbalabala>")
ret.group()
  • 示例4:\number

需求:匹配出<html><h1>www.taobao.com</h1></html>

import re

ret = re.match(r"<(\w*)><(\w*)>.*</\2></\1>", "<html><h1>www.taobao.com</h1></html>")
ret.group()

ret = re.match(r"<(\w*)><(\w*)>.*</\2></\1>", "<html><h1>www.taobao.com</h2></html>")
ret.group()
  • 示例5:(?P<name>) (?P=name)

需求:匹配出<html><h1>www.taobao.com</h1></html>

import re

ret = re.match(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.taobao.com</h1></html>")
ret.group()

ret = re.match(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.taobao.com</h2></html>")
ret.group()

(?P<name>)和(?P=name)中的字母P大寫

8、re模塊的高級用法

8.1search

需求:匹配出文章閱讀的次數(shù)
import re

ret = re.search(r"\d+", "閱讀次數(shù)為 9999")
print(ret.group())

9999

8.2findall

需求:統(tǒng)計出python、c、c++相應文章閱讀的次數(shù)
import re

ret = re.findall(r"\d+", "python = 9999, c = 7890, c++ = 12345")
print(ret)

['9999', '7890', '12345']

8.3sub 將匹配到的數(shù)據(jù)進行替換

需求:將匹配到的閱讀次數(shù)加1
方法1:
import re

ret = re.sub(r"\d+", '998', "python = 997")
print(ret)

python = 998





方法2:
import re

def add(temp):
    strNum = temp.group()
    num = int(strNum) + 1
    return str(num)

ret = re.sub(r"\d+", add, "python = 997 java=100")
print(ret)

ret = re.sub(r"\d+", add, "python = 99")
print(ret)


python = 998 java=101
python = 100
從下面的字符串中取出文本
<div>
        <p>崗位職責:</p>
<p>完成推薦算法、數(shù)據(jù)統(tǒng)計、接口、后臺等服務器端相關(guān)工作</p>
<p><br></p>
<p>必備要求:</p>


re.sub(r'</?\w*>|\n|\s','',s)

8.4split

  • 根據(jù)匹配進行切割字符串,并返回一個列表
需求:切割字符串“info:xiaoZhang 33 shandong”


import re

ret = re.split(r':| ','info:xiaoZhang 33 shandong')
print(ret)


['info', 'xiaoZhang', '33', 'shandong']

9、貪婪和非貪婪

Python里數(shù)量詞默認是貪婪的(在少數(shù)語言里也可能是默認非貪婪),總是嘗試匹配盡可能多的字符;
非貪婪則相反,總是嘗試匹配盡可能少的字符。
在"*","?","+","{m,n}"后面加上?,使貪婪變成非貪婪。

s="This is a number 234-235-22-423"

ret = re.match(".+(\d+-\d+-\d+-\d+)",s)
print(ret.group())

This is a number 234-235-22-423

ret = re.match(".+?(\d+-\d+-\d+-\d+?)",s)
print(ret.group())

This is a number 234-235-22-4

正則表達式模式中使用到通配字,那它在從左到右的順序求值時,會盡量“抓取”滿足匹配最長字符串,在我們上面的例子里面,“.+”會從字符串的啟始處抓取滿足模式的最長字符,其中包括我們想得到的第一個整型字段的中的大部分,“\d+”只需一位字符就可以匹配,所以它匹配了數(shù)字“4”,而“.+”則匹配了從字符串起始到這個第一位數(shù)字4之前的所有字符。
解決方式:非貪婪操作符“?”,這個操作符可以用在"*","+","?"的后面,要求正則匹配的越少越好。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容