Python正則表達式(不)完全詳解

解釋

簡單來說,正則表達式就是一種字符串的匹配模式,查找一個字符串中是否有我們所需要的的子串

在python中正則是在re庫裏面,故我們用正則需要導入這個內置庫

import re

元字符:元字符使正則表達式具有處理能力。所謂元字符就是指那些在正則表達式中具有特殊意義的專用字符,比如這些: * + {} [] () | \ ^ $ 等等

re. match函數

原型: match(pattern, string, flags=0)
參數

  • patter:匹配的正則表達式
  • string:要匹配的字符串
  • flags:標誌位,用於控制正則表達式的匹配方式,值如下
匹配方式 含義
re.I 忽略大小寫
re.L 做本地戶識別
re.M 多行匹配,影響^和$
re.S 使.匹配包括換行符在內的所有字符,沒有此標誌,’.'將匹配除換行符以外的任何內容。
re.U 根據Unicode字符集解析字符,影響\w \W \b \B
re.X 使我們以更靈活的格式理解正則表達式

功能:嘗試從字符串的起始位置匹配一個模式,如果不是起始位置匹配,成功的話,返回None

示例:

print(re.match("www", "www.baidu.com"))    # <_sre.SRE_Match object; span=(0, 3), match='www'>
print(re.match('www', ".bwwwaidu.com"))    # None

掃描整個字符串,返回從起始位置成功的匹配

re.I

含義:忽略大小寫
示例:

print(re.match("www", "wwW.baidu.com", flags=re.I))  # <_sre.SRE_Match object; span=(0, 3), match='wwW'>
re.L

含義:忽略大小寫
讓\w,\W,\b,\B和區分大小寫的匹配取決於當前的語言環境。該標誌只能與字節模式一起使用。不建議使用此標誌,因爲語言環境機制非常不可靠,它一次只能處理一種“區域性”,並且僅適用於8位語言環境。默認情況下,Python 3中已爲Unicode(str)模式啓用了Unicode匹配,並且能夠處理不同的語言環境/語言。
筆者也不知道該怎麼示例,請見諒

re.M

含義:多行匹配,影響^和$
建議:findall()是掃描整個字符串,並返回結果列表
示例:
不使用re.M的效果

# 不使用re.M
s = """
www
.
baidu
.com
awww
"""
print(re.findall("^www", s))

運行結果:

[]

使用re.M的效果

# 使用re.M
s = """
www
.
baidu
.com
awww
"""
print(re.findall("^www", s, flags=re.M))

運行結果:

['www']

結果顯而易見,re.M是每一行都匹配一下

re.S

含義:使.匹配包括換行符在內的所有字符,沒有此標誌,’.'將匹配除換行符以外的任何內容。
建議:search()是掃描整個字符串,並返回第一個成功的匹配
示例:

s = "\nwww.baidu.com"
print(re.search(r".", s))
print(re.search(r".", s, flags=re.S))

運行結果:

<_sre.SRE_Match object; span=(1, 2), match='w'>
<_sre.SRE_Match object; span=(0, 1), match='\n'>
re.U

含義:根據Unicode字符集解析字符,影響\w \W \b \B
筆者個人感覺沒什麼用,將\w \W \s \S等這些元字符按照 Unicode 的標準來考慮
re.U在 Python 3 中沒有了, 只在 Python 2 中才有作用

re.X

含義:這個選項忽略規則表達式中的空白和註釋,並允許使用 ’#’ 來引導一個註釋。這樣可以讓你把規則寫得更美觀些。
示例:

rc = re.compile(r"""
# 開始第一個數字匹配
/d+
# 或者字母
|
# +的意思是匹配更多
[a-zA-Z]+
# 反正這個可以被允許寫註釋
""", re.X)
res = rc.match('abcd')
print(res.group())

運行結果:

abcd

匹配空白符

rc = re.compile(r"""
# 開始匹配規則
# 匹配一個或多個空格,也可以用"\s+"代替
\  +
""", re.X)
res = rc.match('   11')  # 字符串包含三個空格
print(res)
print('+%s+' % res.group())

運行結果:

<_sre.SRE_Match object; span=(0, 3), match='   '>
+   +
re. findall函數

原型: findall(pattern, string, flags=0)
參數

  • patter:匹配的正則表達式
  • string:要匹配的字符串
  • flags:標誌位,用於控制正則表達式的匹配方式,值如上

功能:掃描整個字符串,並返回結果列表

print(re.findall("ww", "fbeaskfww"))  # <_sre.SRE_Match object; span=(7, 9), match='ww'>
re. search函數

原型: search(pattern, string, flags=0)
參數

  • patter:匹配的正則表達式
  • string:要匹配的字符串
  • flags:標誌位,用於控制正則表達式的匹配方式,值如上

功能:掃描整個字符串,並返回第一個成功的匹配

print(re.search("ww", "wwhuhdiww"))  # ['ww', 'ww']

匹配單個字符與數字

匹配方式 含義
.<–(這是個點,顏色有點淺) 匹配除換行符以外的任意字符
[0123456789] []是字符集合,表示匹配方括號中所包含的任意一一個字符
[jack] 匹配’j’, ‘a’, ‘c’, 'k’中任意一個字符
[a-z] 匹配任意小寫字母
[A-Z] 匹配任意大寫字母
[0-9] 匹配任意數字,類似[0123456789]
[0-9a-zA- z] 匹配任意的數字和字母
[0-9a-zA-Z_] 匹配任意的數字、字母和下劃線
[^jack] 匹配除了’j’, ‘a’, ‘c’, 'k’這幾個字母以外的所有字符,中括號裏的^稱爲脫字符,表示不匹配集合中的字符
[^0-9] 匹配所有的非數字字符
\d 匹配數字,效果同[0-9]
\D 匹配非數字字符,效果同[^ 0-9]
\w 匹配數字,字母和下劃線,效果同[0-9a-zA-Z_]
\W 匹配非數字,字母和下劃線,效果同[^0-9a-zA-Z]
\s 匹配任意的空白符(空格,換行,回車,換頁,製表),效果同[ \f\n\r\t]
\S 匹配任意的非空白符,效果同[^ \f\n\r\t]

舉個例子(其他的都差不多,這個暫舉4個例子):

print(re.findall(".", "jack"))             # ['j', 'a', 'c', 'k']
print(re.findall("[a-z]", "jack"))         # ['j', 'a', 'c', 'k']
print(re.findall("[0-9]", "jack123"))      # ['1', '2', '3']
print(re.findall("[^jack]", "jack123"))    # ['1', '2', '3']

錨字符(邊界字符)

匹配方式 含義
^ 行首匹配,和在[]裏的^不是一個意思
$ 行尾匹配
\A 匹配字符串開始,它和^的區別是,\A只匹配整個字符串的開頭,即使在re.M模式下也不會匹配它的行首
\Z 匹配字符串行尾,它和$的區別是,\A只匹配整個字符串的行尾,即使在re.M模式下也不會匹配它的行尾首
\b 匹配一個單詞的邊界,也就是指單詞與空格間的位置('boy’可以匹配Niceboy,但是不能匹配單詞的中間)
\B 匹配一個非單詞邊界

舉個例子(其他的都差不多,這個暫舉3個例子):

print(re.search("^jack", "jack is a good man"))     # <_sre.SRE_Match object; span=(0, 4), match='jack'>
print(re.search("jack$", "The cat is this jack"))   # <_sre.SRE_Match object; span=(16, 20), match='jack'>
print(re.search("\Ajack", "jack is a nice boy"))    # <_sre.SRE_Match object; span=(0, 4), match='jack'>
\A^的區別
print(re.findall("^jack", "jack is good boy\njack is good boy", re.M))     # ['jack', 'jack']
print(re.findall("\Ajack", "jack is good boy\njack is good boy", re.M))    # ['jack']
\Z$的區別
print(re.findall("boy$", "jack is good boy\njack is good boy", re.M))  # ['boy', 'boy']
print(re.findall("boy\Z", "jack is good boy\njack is good boy", re.M))  # ['boy']
\b\B
print(re.search(r"boy\b", "Niceboy"))  # <_sre.SRE_Match object; span=(4, 7), match='boy'>
print(re.search(r"ce\b", "Niceboy"))  # None
print(re.search(r"boy\B", "Niceboy"))  # None
print(re.search(r"ce\B", "Niceboy"))  # <_sre.SRE_Match object; span=(2, 4), match='ce'>

匹配多個字符

說明:下方的x、 y、z均爲假設的普通字符,不是正則表達式的元字符

匹配方式 含義
x? 匹配0個或者1個x 非貪婪匹配
x* 匹配0個或者任意多個x 貪婪匹配
x+ 匹配至少一個x 貪婪匹配
x{n} 匹配確定的n個x (n是一個非負整數)
x{n,} 匹配至少n個x 貪婪匹配
x{n,m} 匹配至少n個x最多m個x 注意:n <= m
x|y | 表示或,匹配的是x或y
(xyz) 匹配小括號內的xyz(作爲一個整體去匹配)
a?

匹配0個或者1個a
非貪婪匹配(儘可能少的匹配)

print(re.findall(r"a?", "jack is a boy"))  # ['', 'a', '', '', '', '', '', '', 'a', '', '', '', '', '']

因爲它可以匹配0個,所以會有’ '的存在

a*

匹配0個或者任意多個a
貪婪匹配(儘可能多的匹配)

print(re.findall(r"a*", "aaabaa"))  # ['aaa', '', 'aa', '']

因爲它可以匹配0個,所以會有’ '的存在

a+

匹配至少一個a
貪婪匹配(儘可能多的匹配)

print(re.findall(r"a+", "aaabaaaa"))  # ['aaa', 'aaaa']
a{n}

匹配確定的n個a (a是一個非負整數)

print(re.findall(r"a{3}", "aaabaaaa"))  # ['aaa', 'aaa']
a{n,}

匹配至少n個a
貪婪匹配(儘可能多的匹配)

print(re.findall(r"a{3,}", "aaabaaaa"))  # ['aaa', 'aaaa']
a{n,m}

匹配至少n個x最多m個x 注意:n <= m

print(re.findall(r"a{3,6}", "aaaabaaaaaaaa"))  # ['aaaa', 'aaaaaa']
a|b

| 表示或,匹配的是a|b

print(re.findall(r"a|A", "aaabaAaa"))  # ['a', 'a', 'a', 'a', 'A', 'a', 'a']
(abc)

匹配小括號內的abc(作爲一個整體去匹配)

print(re.findall(r"((j|J)ack)", "jack--Jack"))  # [('jack', 'j'), ('Jack', 'J')]

特殊

*? +? x?

最小匹配,通常都是儘可能多的匹配,可以使用這種解除貪婪匹配
(?:x)

類似(xyz),但不表示一個組

例子:

# /* part1 */ /* part2 */
print(re.findall(r"//*.*/*/", r"/* part1 */ /* part2 */"))      # ['/* part1 */ /* part2 */']
print(re.findall(r"//*.*?/*/", r"/* part1 */ /* part2 */"))     # ['/* part1 */', '/* part2 */']

儘可能少的去匹配
這裏解釋一下:

  • //*中的第一個斜槓,實際上就是斜槓。第二個斜槓是轉義的*
  • 中間的.*.代表除換行符以外的任意字符嘛,*是0個或者任意多個.嘛,相當於任意多個換行符以外的字符

re模塊的深入

re.split函數 – -- – 優秀的字符串切割加工廠

這是普通的字符串切割

str1 = "jack   is  a  good   boy"
# 這是普通的字符串切割
print(str1.split(" "))                   # ['jack', '', '', 'is', '', 'a', '', 'good', '', '', 'boy']

如果要去除這些小空格的話,還有用循環之後判斷來去除,挺麻煩的(好吧,其實也不是特別麻煩)

下面我們用re.split函數來切割一下

str1 = "jack   is   a   good   boy"
print(re.split(r" +", str1))             # ['jack', 'is', 'a', 'good', 'boy']

這裏的+前面是有小空格的,小空格+組合起來,就是匹配至少一個空格,然後直接去除

re. finditer函數

原型: finditer (pattern,string, flags=0)
參數:

  • patter:匹配的正則表達式
  • string:要匹配的字符串
  • flags:標誌位,用於控制正則表達式的匹配方式

功能:與findall類似, 掃描整個字符串,返回的是一個迭代器

str2 = "jack is a good boy! jack is a good boy! jack is a good boy!"
d = re.finditer(r"(jack)", str2)
while True:
    try:
        l = next(d)
        print(l)
    except StopIteration as e:
        break

運行結果:

<_sre.SRE_Match object; span=(0, 4), match='jack'>
<_sre.SRE_Match object; span=(20, 24), match='jack'>
<_sre.SRE_Match object; span=(40, 44), match='jack'>

因爲是迭代器,所以它如果最後取不到值的話,會報錯的,故我們要這裏取到錯誤之後終止程序

re.subre.subn函數

字符串的替換和修改
原型:sub (pattern, repl, string, count=0)
原型:subn (pattern, repl, string, count=0)
參數

  • pattern:正則表達式 (規則)
  • repl:指定的用來替換的字符串
  • string:目標字符串
  • count:最多替換次數

功能: 在目標字符串中以正則表達式的規則匹配字符串,再把他們替換成指定的字符串。可以指定替換的次數,如果不指定,替換所有的匹配字符串

區別

  • sub返回一個被替換的字符串
  • subn返回一個元組,第一個元素被替換的字符串,第二個元素表示被替換的次數
str3 = "jack is a good good good boy"
print(re.sub(r"(good)", "nice", str3))                 # jack is a nice nice nice boy
print(type(re.sub(r"(good)", "nice", str3)))           # <class 'str'>
print(re.subn(r"(good)", "nice", str3))                # ('jack is a nice nice nice boy', 3)
print(type(re.subn(r"(good)", "nice", str3)))          # <class 'tuple'>

分組

概念:除了簡單的判斷是否匹配之外,正則表達式還有提取子串的功能。用()表示的就是提取分組

例子:

  • 使用序號獲取對應組的信息,group(0)一直代表的原始字符串
str4 = "110-123456"
m = re.match(r"(\d{3})-(\d{6})", str4)
print(m.group(0))                  # 110-123456
print(m.group(1))                  # 110
print(m.group(2))                  # 123456
  • 查看匹配的各組的情況
print(m.groups())                  # ('110', '123456')
  • 命名 (?P<名字>)
t = re.match(r"(?P<first>\d{3})-(?P<last>\d{6})", str4)
print(t.group("first"))            # 110

re.compile函數

原型: compile(pattern,flags=0)
參數

  • patter:要編譯的正則表達式
  • flags(一般我們不用):標誌位,用於控制正則表達式的匹配方式

編譯:當我們使用正則表達式時,re模塊會幹兩件事

  1. 編譯正則表達式,如果正則表達式本身不合法,會報錯
  2. 用編譯後的正則表達式去匹配對象

我們普通的使用一個match函數

pat = r"^1(([3578]\d)|(47))\d{8}$"
print(re.match(pat, "13000000000"))                # <_sre.SRE_Match object; span=(0, 11), match='13000000000'>

編譯成正則對象後

pat = r"^1(([3578]\d)|(47))\d{8}$"
re_telephone = re.compile(pat)
print(re_telephone.match("13000000000"))           # <_sre.SRE_Match object; span=(0, 11), match='13000000000'>

好吧,其實是一樣的,但是帥的人都用編譯的方式
因爲,簡單快捷,編譯成對象之後我們可以直接使用對象就行了,這樣方便一點

感謝觀看,如有疑問或補充的,不勝感激!!

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