Python基础篇(九)-- 正则表达式
????????正則表達式是一種用來匹配字符串的強有力的武器。它的設計思想是用一種描述性的語言來給字符串定義一個規則,凡是符合規則的字符串,我們就認為它“匹配”了,否則,該字符串就是不合法的。
1 正則表達式
1.1 定位符
????????行定位符就是用來描述字符串的邊界,“^”表示行的開始,“$”表示行的結尾。
^tm # 表示要匹配字符串tm的開始位置是行頭 tm$ # 表示要匹配字符串tm的結束位置是行尾1.2 元字符
????????除了上一節介紹的元字符“^”和“$”外,正則表達式還有更多的元字符,見下圖。
圖1 常用元字符
????????假設你在一篇英文小說里查找hi,你可以使用正則表達式hi。不幸的是,很多單詞里包含hi這兩個連續的字符,比如him,history,high等等。用hi來查找的話,這里邊的hi也會被找出來。如果要精確地查找hi這個單詞的話,我們應該使用\bhi\b。
????????\b是正則表達式規定的一個特殊代碼(某些地方叫它元字符,metacharacter),代表著單詞的開頭或結尾,也就是單詞的分界處。雖然通常英文的單詞是由空格,標點符號或者換行來分隔的,但是\b并不匹配這些單詞分隔字符中的任何一個,它只匹配一個位置。
1.3 限定符
????????我們知道,使用(\w*)匹配任意數量的字母或數字,如果想匹配特定數量的數字,就需要使用限定符(指定數量的字符)來實現該功能,如果匹配8位QQ號可用如下表達式:
^\d{8}$圖2 常用限定符
1.4 字符類
????????正則表達式查找數字和字母是很簡單的,因為已經有了對應這些字符集合的元字符(如\d、\w),但是如果要匹配沒有預定義元字符的字符集合(比如元音字母a, e, i, o, u),應該怎么辦?
????????很簡單,只需要在方括號里列出它們就行了,像[aeiou]可以匹配任何一個英文元音字母,[.?!]匹配標點符號(“.” “?”或“!”)。也可以輕松地指定一個字符范圍,像[0-9]代表的含義與\d就是完全一致的:一位數字;同理,[a-z0-9A-Z_]完全等同于\w(如果只考慮英文的話)。
????????說明:要想匹配給定字符串中任意一個漢字,可以使用[\u4e00-\u9fa5];如果要匹配連續多個漢字,可以使用[\u4e00-\u9fa5]+。
1.5 排除字符
????????在1.1小節列出的是匹配符合指定字符集合的字符串。現在反過來,匹配不符合指定字符集合的字符串。正則表達式提供了^字符。這個元字符在1.1小節中出現過,表示行的開始。而這里將會放到方括號中,表示排除的意思。例如:
[^a-zA-Z]????????該表達式用于匹配一個不是字母的字符串。
1.6 選擇字符
????????試想一下,如何匹配身份證號碼?首先需要了解一下身份證號碼的規則。身份證號碼長度為15位或者18位。如果為15位時,則全為數字;如果為18位時,前17位為數字,最后一位是校驗位,可能為數字或字符X。
在上面的描述中,包含著條件選擇的邏輯,這就需要使用選擇字符(|)來實現。該字符可以理解為‘或’,匹配身份證的表達式可以寫成如下方式:
????????該表達式的意思是以匹配15位數字,或者18位數字,或者17位數字和最后一位。最后一位可以是數字,也可以是X或者x。
1.7 轉義字符
????????正則表達式中的轉義字符()和Python中的大同小異,都是將特殊字符(如“”“?”“|”等)變為普通的字符。舉一個IP地址的實例,用正則表達式匹配諸如“127.0.0.1”格式的IP地址。如果直接使用點字符,格式為:
[1-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}????????這顯然不對,因為“.”可以匹配一個任意字符。這時,不僅是127.0.0.1這樣的IP,連127101011這樣的字符串也會被匹配出來。所以在使用“.”時,需要使用轉義字符)。修改后上面的正則表達式格式為:
[1-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}1.8 分組
????????通過1.6小節中的例子,相信讀者已經對小括號的作用有了一定的了解。小括號字符的第一個作用就是可以改變限定符的作用范圍,如“|”、“*”、“^”等。例如下面的表達式中包含小括號。
(six|four)th????????這個表達式的意思是匹配單詞sixth或fourth,如果不使用小括號,那么就變成了匹配單詞six和fourth了。
小括號的第二個作用是分組,也就是子表達式。如(\.[0-9]{1,3}){3},就是對分組(\.[0-9]{1,3})進行重復操作。
????????由于模式字符串中可能包括大量的特殊字符和反斜杠,所以需要寫為原生字符串,即在模式字符串前加r或R。例如,模式字符串采用原生字符串表示為:
r`\bm\w*\b`????????推薦幾個正則表達式在線測試工具,
- 菜鳥工具:https://c.runoob.com/front-end/854/
- Regulex:https://jex.im/regulex/#!flags=&re=%5B0-9%5D%2B
- RegExr:https://regexr.com/
2 Re模塊
????????Python提供了re模塊,用于實現正則表達式的操作。在實現時,可以使用re模塊提供的方法(如search()、match()、findall()等)進行字符串處理,也可以先使用re模塊的compile()方法將模式字符串轉換為正則表達式對象,然后再使用該正則表達式對象的相關方法來操作字符串。下面是re模塊中的核心函數。
2.1 編譯表達式
????????compile函數用于編譯正則表達式,生成一個正則表達式(Pattern)對象,供 match()和search()這兩個函數使用。]
參數說明:
- pattern:表示模式字符串,由要匹配的正則表達式轉換而來。
- flags:可選參數,表示標志位,用于控制匹配方式,如是否區分字母大小寫。常用的標志如圖3所示。
圖3 常用標志
語法格式為:
re.compile(pattern[, flags])2.2 匹配字符串
????????匹配字符串可以使用re模塊提供的match()、search()、findall()等方法。
1. 使用match()方法進行匹配
????????match()方法用于從字符串的開始處進行匹配,如果在起始位置匹配成功,則返回Match對象,否則返回None。其語法格式如下:
re.match(pattern, string, [flags])參數說明:
- pattern:表示模式字符串,由要匹配的正則表達式轉換而來。
- string:表示要匹配的字符串。
- flags:可選參數,表示標志位,用于控制匹配方式,如是否區分字母大小寫。常用的標志如圖3所示。
例如,匹配字符串是否以mr_開頭,不區分字母大小寫,代碼如下:
import re pattern = re.compile(r'mr_\w+', re.I) # 模式字符串,不區分大小寫 string1 = 'MR_SHOP mr_shop' # 要匹配的字符串 m1 = pattern.match(string1) print(m1) # <re.Match object; span=(0, 7), match='MR_SHOP'> string2 = '項目名稱 MR_SHOP mr_shop' m2 = pattern.match(string2) print(m2) # None????????由上面的結果我們可以看到,match()方法從字符串的開始位置開始匹配,如果匹配成功,則返回一個Match對象包含了匹配值的位置和匹配數據。其中,要獲取匹配值的起始位置可以使用Match對象的start()方法;要獲取匹配值的結束位置可以使用end()方法;通過span()方法可以返回匹配位置的元組;通過string屬性可以獲取要匹配的字符串。例如下面的代碼:
import repattern = re.compile(r'mr_\w+', re.I) # 模式字符串,不區分大小寫 string1 = 'MR_SHOP mr_shop' # 要匹配的字符串 m1 = pattern.match(string1)print('匹配值的起始位置:', m1.start()) print('匹配值的結束位置:', m1.end()) print('匹配位置的元組:', m1.span()) print('要匹配的字符串:', m1.string) print('匹配數據:', m1.group())執行結果如下:
匹配值的起始位置: 0
匹配值的結束位置: 7
匹配位置的元組: (0, 7)
要匹配的字符串: MR_SHOP mr_shop
匹配數據: MR_SHOP
2. 使用search()方法進行匹配
????????search()方法用于在整個字符串中搜索第一個匹配的值,如果匹配成功,則返回Match對象,否則返回None。search()方法的語法格式如下:
參數說明:
- pattern:表示模式字符串,由要匹配的正則表達式轉換而來。
- string:表示要匹配的字符串。
- flags:可選參數,表示標志位,用于控制匹配方式,如是否區分字母大小寫。
????????搜索第一個以mr_開頭的字符串,不區分字母大小寫,代碼如下:
import repattern = re.compile(r'mr_\w+', re.I) # 模式字符串,不區分大小寫 string1 = 'MR_SHOP mr_shop' # 要匹配的字符串 match = pattern.search(string1) print(match) string2 = '項目名稱 MR_SHOP mr_shop' match = pattern.search(string2) print(match)執行結果如下:
<re.Match object; span=(0, 7), match=‘MR_SHOP’>
<re.Match object; span=(5, 12), match=‘MR_SHOP’>
????????findall()方法用于在整個字符串中搜索所有符合正則表達式的字符串,并以列表的形式返回。如果匹配成功,則返回包含匹配結構的列表,否則返回空列表。findall()方法的語法格式如下:
re.findall(pattern, string, [flags])- pattern:表示模式字符串,由要匹配的正則表達式轉換而來。
- string:表示要匹配的字符串。
- flags:可選參數,表示標志位,用于控制匹配方式,如是否區分字母大小寫。
????????搜索以mr_開頭的字符串,不區分字母大小寫,代碼如下:
import repattern = re.compile(r'mr_\w+', re.I) # 模式字符串,不區分大小寫 string1 = 'MR_SHOP mr_shop' # 要匹配的字符串 m1 = pattern.match(string1) string2 = '項目名稱 MR_SHOP mr_shop' m2 = pattern.match(string2) match = pattern.findall(string1) print(match) match = pattern.findall(string2) print(match)執行結果如下:
[‘MR_SHOP’, ‘mr_shop’]
[‘MR_SHOP’, ‘mr_shop’]
2.3 替換字符串
????????sub()方法用于實現字符串替換,語法格式如下:
re.sub(pattern, repl, string, count, flags)參數說明:
- pattern:表示模式字符串,由要匹配的正則表達式轉換而來。
- repl:表示替換的字符串。
- string:表示要被查找替換的原始字符串。
- count:可選參數,表示模式匹配后替換的最大次數,默認值為0,表示替換所有的匹配。
- flags:可選參數,表示標志位,用于控制匹配方式,如是否區分字母大小寫。
????????替換敏感字符,代碼如下:
import re pattern = re.compile(r'(黑客)|(抓包)|(監聽)|(Trojan)') string = "我是一名程序員,我喜歡看黑客方面的書,想研究一下Trojan。\n" sub = pattern.sub('@_@', string) print(sub) # 輸出為:我是一名程序員,我喜歡看@_@方面的書,想研究一下@_@。2.4 分割字符串
????????split()方法用于實現根據正則表達式分割字符串,并以列表的形式返回。其作用同字符串對象的split()方法類似,所不同的就是分割字符由模式字符串指定。split()方法的語法格式如下:
re.split(pattern, string, [maxsplit], [flags])參數說明:
- pattern:表示模式字符串,由要匹配的正則表達式轉換而來。
- string:表示要匹配的字符串。
- maxsplit:可選參數,表示最大的拆分次數。
- flags:可選參數,表示標志位,用于控制匹配方式,如是否區分字母大小寫。
????????例如,從給定的URL地址中提取出請求地址和各個參數,代碼如下:
pattern = re.compile(r'[?|&]') url = 'http://www.mingrisoft.com/login.jsp?username="mr"&pwd="mrsoft"' result = pattern.split(url) print(result) # 輸出為:['http://www.mingrisoft.com/login.jsp', 'username="mr"', 'pwd="mrsoft"']小結:
| re.compile(pattern, flags=0) | 編譯正則表達式返回正則表達式對象 |
| re.match(pattern, string, flags=0) | 用正則表達式匹配字符串 成功返回匹配對象 否則返回None |
| re.search(pattern, string, flags=0) | 搜索字符串中第一次出現正則表達式的模式 成功返回匹配對象 否則返回None |
| re.split(pattern, string, maxsplit=0, flags=0) | 用正則表達式指定的模式分隔符拆分字符串 返回列表 |
| re.sub(pattern, repl, string, count=0, flags=0) | 用指定的字符串替換原字符串中與正則表達式匹配的模式 可以用count指定替換的次數 |
| re.fullmatch(pattern, string, flags=0) | match函數的完全匹配(從字符串開頭到結尾)版本 |
| re.findall(pattern, string, flags=0) | 查找字符串所有與正則表達式匹配的模式 返回字符串的列表 |
| re.finditer(pattern, string, flags=0) | 查找字符串所有與正則表達式匹配的模式 返回一個迭代器 |
| re.purge() | 清除隱式編譯的正則表達式的緩存 |
| re.I / re.IGNORECASE | 忽略大小寫匹配標記 |
| re.M / re.MULTILINE | 多行匹配標記 |
參考
- 正則表達式30分鐘入門教程:https://deerchao.cn/tutorials/regex/regex.htm
- 字符串和正則表達式:https://github.com/jackfrued/Python-100-Days/blob/master/Day01-15
- Python3 正則表達式:https://www.runoob.com/python3/python3-reg-expressions.html
總結
以上是生活随笔為你收集整理的Python基础篇(九)-- 正则表达式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小程序转uni-app——动态转换样式
- 下一篇: websocket python爬虫_p