python re模組 正規表示式

非真發表於2018-09-12

導航:

1、正規表示式元字元
2、預定義字符集
3、re模組常用函式
4、注意事項

正規表示式在很多語言裡都支援,python也不例外,re模組就是正規表示式的應用

正規表示式對字串的邏輯操作,主要是對字串的一種過濾,用“元字元” 與“普通字元”組成一個字串規則對已知的字串或文字過濾出自己想要的字串

1、正規表示式元字元

轉義字元,將後邊緊跟著的字元變成特殊字元,或將後邊的特殊字元變成普通字元

如:在正規表示式中,”
“換行符,”\”則代表一個普通字元””

^ 匹配第一行行首,匹配多行需要傳參 flags=re.MULTILINE
$ 匹配最後一行行尾,匹配多行需要傳參 flags=re.MULTILINE
. 除”
“”
“外,匹配任意的單個字元,要使”.”匹配換行符,flags=re.DOTALL
| 或,如 “aaa|bbb|ccc”,表示”aaa”,”bbb”,”ccc”三選一
? 匹配前邊的子表示式0次或1次,等價於{0,1}
+ 匹配前邊的子表示式1次或多次,等價於{1,}
* 匹配前邊的子表示式0次或多次,,等價於{0,}
{}

{n}匹配前邊的子表示式n次,{n,}匹配前邊的子表示式至少n次 即:>= n,

{n,m}匹配前邊的子表示式n~m次,即:n<= 表示式 <=m

() 分組,從1開始,從左至右數”(“為第幾組,下標0為全部分組
[]

字符集匹配[]中的人一個字元,之匹配一次,如[abc]:表示”a”,”b”,”c”三選一。

也可以給定範圍(必須是連續的才行),如[a-z]:表示a到z任意一個字元。

還可以取反,如[^abc]:除”a”,”b”,”c”外的任意字元。

注:[]中只有”^”,”-“,””三個特殊字元,其中””代表轉義字元,

其它的都代表原本普通的字元,如:[.]只是一個普通的點字元

:要使用元字元本身的普通字元,請使用轉義字元轉義一下,如 :”(” 在正規表示式中代表普通給”(“字元,其它的雷同

分組的用法:

(
um)
引用指定第幾分組的值
(?P<name>) 指定分組別名”name”
(?P=name) 引用指定別名的分組的值
(?:)

相當於去分組化,變成”與”()子集,

如:”abc(?:qqq|www)”–>相當於”abcqqq|abcwww”

(具體用法請看下邊(search函式))

 

2、預定義字符集

匹配一個單詞邊界,也就是指單詞和空格間的位置,

其它特殊字元也可以是單詞的邊界,如”#”,”$”,”&”,”*”等

B 匹配非單詞邊界
d 匹配一個數字字元。等價於[0-9]
D 匹配一個非數字字元。等價於[^0-9
s

匹配任何不可見字元,包括空格、製表符、換頁符等,

等價於[ f

v]

S 匹配任何可見字元。等價於[^ f

v]

w

匹配包括下劃線的任何單詞字元。這裡的”單詞”字元使用Unicode字符集,

類似但不等價於“[A-Za-z0-9_]”,還包含漢字等它國字元

W

匹配任何非單詞字元。這裡的”單詞”字元使用Unicode字符集,

類似但不等價於“[^A-Za-z0-9_]”,還包含漢字等它國字元

 

 3、re模組常用函式

在這裡我要先說明一下 flags 的用法

re.A 或 re.ASCII 使用ASCII字符集進行匹配(不常用)
re.I 或 re.IGNORECASE 忽略大小寫匹配
re.L 或 re.LOCALE

使用當前預定字元類 w W B s S

取決於當前區域設定(不常用)

re.U 或 re.UNICODE

使用Unicode字元類 w W B s S d D

取決於unicode定義的字元屬性(不常用)

re.M 或 re.MULTILINE 多行匹配,使”^”,”$”可以在每一行中都進行匹配
re.S 或 re.DOTALL 使 “.” 可以匹配換行符”
“,”
re.X 或 re.VERBOSE 去掉正規表示式中的所有空格符(不常用)

 

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

按照規則匹配整個字串,返回匹配結果的列表

 1 >>> re.findall(r"hello", "hello world hello")  # 普通匹配
 2 [`hello`, `hello`]
 3 >>> re.findall(r"^hello", "hello world hello")  # 匹配開頭
 4 [`hello`]
 5 >>> re.findall(r"^hello", "hello world
hello", flags=re.MULTILINE)  # 多行匹配開頭
 6 [`hello`, `hello`]
 7 >>> re.findall(r"hello$", "hello world hello")  # 匹配結尾
 8 [`hello`]
 9 >>> re.findall(r"d+", "aaa111bbb222ccc333")  # 匹配數字
10 [`111`, `222`, `333`]
11 >>> re.findall(r"d{2}", "aaa111bbb222ccc333")  # 匹配兩位的數字
12 [`11`, `22`, `33`]
13 >>> re.findall(r"ab|cd", "ab000cd00")  # 匹配"ab"或"cd"
14 [`ab`, `cd`]
15 >>> re.findall(r"(", "ab(cd"))  # 匹配"("
16 [`(`]
17 
18 >>> re.findall(r"(abc)+", "abcabcabc")  # 想要匹配多個"abc",使用分組時會優先把分組的內容返回
19 [`abc`]
20 >>> re.findall(r"(?:abc)+", "abcabcabc")  # 想要匹配多個"abc",(?:)把分組去掉,變成一個普通的字串
21 [`abcabcabc`]

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

finditer與findall相似,只不過finditer返回一個迭代器,迭代器中每一個元素都是re.Match物件,通過group()可以獲取值

1 r = re.finditer("hello", "hello world hello")
2 for i in r:
3     print(i.group())
4 
5 # 輸出結果
6 hello
7 hello

 

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

search函式只返回第一個匹配到的結果,成功返回re.Match物件,否則返回None。

 1 >>> re.search(r"hello", "hello world hello")
 2 <_sre.SRE_Match object; span=(0, 5), match=`hello`>  # 可以看到只返回了第一個"hello"
 3 >>> re.search(r"hello", "hello world hello").group()
 4 `hello`
 5 
 6 >>> re.search(r"(abc) 1", "abc abc").group()  # 1 引用分組1的值
 7 `abc abc`
 8 >>> re.search(r"(?P<name>abc) (?P=name)", "abc abc").group()  # (?P=name) 引用分組別名"name"的值
 9 `abc abc`
10 
11 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group()
12 `zhansan 23`
13 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group(0)  # 分組0--即匹配的結果
14 `zhansan 23`
15 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group(1)  # 分組1的值
16 `zhansan`
17 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group(2)  # 分組2的值
18 `23`
19 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group("name")  # 分組別名name的值
20 `zhansan`
21 >>> re.search(r"(?P<name>zhansan) (?P<age>23)", "zhansan 23").group("age")  # 分組別名age的值
22 `23`

 

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

match從開始處進行匹配,成功返回re.Match物件,否則返回None。類似於於findall程式碼中的第3行

1 >>> re.findall(r"^abc", "abcooooo")
2 [`abc`]
3 >>> re.match(r"abc", "abcooooo").group()
4 `abc`

 

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

sub按照給定的規則將string字串中的相應的片段替換為repl,count 最多替換的次數,count=0預設為全部替換,返回替換後的字串

1 >>> re.sub(r"d+", "$", "aaa1bb2ccc333")  # 將連續的數字變成"$"
2 `aaa$bb$ccc$`

 

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

與sub相識,count 最多替換的次數,count=0預設為全部替換,返回 一個元組,下標0為替換後的字串,下標1成功替換的次數

1 >>> re.subn(r"d+", "$", "aaabbccc")
2 (`aaabbccc`, 0)
3 >>> re.subn(r"d+", "$", "aaa11bb22ccc")
4 (`aaa$bb$ccc`, 2)
5 >>> re.subn(r"d+", "$", "aaa11bb22ccc", 1)  # 最多替換1次
6 (`aaa$bb22ccc`, 1)
7 >>> re.subn(r"d+", "$", "aaa11bb22ccc", 10)  # 最多替換10次
8 (`aaa$bb$ccc`, 2)  # 成功替換2次

 

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

通過給定規則,將string進行切割,maxsplit最多切割次數,maxsplit=0預設全部切割,返回切割結果的字串列表

1 >>> re.split(r"@", "a#b#c#d#e")  # 沒有找到"@",不切割
2 [`a#b#c#d#e`]
3 >>> re.split(r"#", "a#b#c#d#e")  # 按"#"對字串進行切割
4 [`a`, `b`, `c`, `d`, `e`]
5 >>> re.split(r"#", "a#b#c#d#e", 2)  # 按"#"對字串進行切割,最多切割2次
6 [`a`, `b`, `c#d#e`]

 

8)re.compile(pattern, flags=0)

返回一個正規表示式的物件

1 >>> rg = re.compile(r"d+", flags=0)
2 >>> re.findall(rg, "a1bb22ccc333")
3 [`1`, `22`, `333`]

 

4、注意事項

1)”r” 原生字串的使用,在字串前加 “r” 或 “R” 表示這個字串為原生字串,即所有的字元都表示普通字元,無特殊字元,常在正則、路徑中應用

1 >>> print(r"aa
bb")
2 aa
bb
3 >>> print(len(r"aa
bb"))
4 6
5 >>> print("aa
bb")
6 aa
7 bb
8 >>> print(len("aa
bb"))
9 5

可以看到第四行,字串長度為”6″ ,即 “” “n” 是兩個字元。

第6、7行輸出了兩行,第9行字串長度”5″,說明 ”
”  是一個換行符

 

2)例子:如果需要匹配 “” 該如何寫正規表示式(重點)

1 >>> re.findall(r"aa\", r"aab")
2 [`aa\`]
3 >>> re.findall("aa\", r"aab")
4 Traceback (most recent call last):
5   # 報錯內容····太多,就這樣顯示就好
6 >>> re.findall("aa\\", r"aab")
7 [`aa\`]
8 >>> print(len(re.findall(r"aa\", r"aab")[0]))
9 3

在這裡首先要說明一下,在python中,輸出帶引號的字串中有 “” 字元,是轉義後看到的字元,即 “\”

 

可以看到,在匹配帶轉義字元的正規表示式的中帶 “r” 和不帶 “r” 的寫法有很大的區別

其中的原因是python直譯器在解釋字串的時候會按自己的規則將字串翻譯了一便。

如第3行,”aa\” 經過python 直譯器翻譯之後,已經變成了  r”aa” 這樣的原生字串,傳遞給re模組的時候,re模組無法解析單個 “” 轉義字元,所以會報錯。

如果要匹配  “”  的普通字元,正規表示式需要寫出 “\” ,所以第6行傳遞的時候需要 4 個”\\” ,經過python解釋之後,變成 r”\” 就正確了。

 

綜上所述,在寫正規表示式的時候還是在前邊加個 “r” 這樣或許會避免很多的問題(個人建議,特別是在網上找的正規表示式)

 

相關文章