正則表達式
正則表達式:一種字符串匹配的規則
字符組
字符組 : [字符組] 在同一個位置可能出現的各種字符組成了一個字符組,在正則表達式中用[]表示 字符分為很多類,比如數字、字母、標點等等。 假如你現在要求一個位置"只能出現一個數字",那么這個位置上的字符只能是0、1、2...9這10個數之一。
| 正則 | 待匹配字符 | 匹配結果 | 說明 |
| [0123456789] | 6 | True | 在一個字符組里枚舉合法的所有字符,字符組的任意一個字符和"待匹配字符"相同都視為可匹配 |
| [0123456789] | a | False | 由於字符組中沒有“a”,所以不能匹配 |
| [0-9] | 7 | True | 匹配0-9中的任意數字;等於[0123456789] |
| [a-z] | s | True | 匹配a-z中任意小寫字母。 |
| [A-Z] | B | True | 匹配A-Z中任意大寫字母。 |
| [0-9a-zA-Z] | e | True | 匹配任意數字、大小寫字母。 |
字符
| 元字符 | 匹配內容 |
| . | 匹配除換行符以外的任意字符 |
| \w | 匹配字母或數字或下划線 |
| \s | 匹配任意的空白符:空格、tab、換行;等於[\f\n\r\t] |
| \d | 匹配數字;等於[0-9] |
| \W | 匹配非字母或數字或下划線,也就是說除了字母、數字、下划線以外的 |
| \S | 匹配非任意的空白符,也就是說除了空格、tab、換行以外的;等於[^ \f\n\r\t] |
| \D | 匹配非數字,也就是說除了數字以外的 |
| \t | 匹配一個制表符,tab |
| \n | 匹配一個換行符 |
| ^ | 匹配字符串以什么開頭的 |
| $ | 匹配字符串以什么結尾的 |
| a|b | 匹配字符a或者字符b,| 或者的關系 |
| () | 匹配括號內的表達式,也表示一個組 |
| [...] | 匹配字符組中的字符 |
| [^...] | 匹配非字符組中的所有字符 |
| \b | 匹配一個單詞的邊界 |
注意這三種的結果都表示匹配所有:[\d\D]、[\s\S]、[\w\W]
量詞
| 量詞 | 用法說明 |
| * | 重復零次或者多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價於{0,}。 |
| + | 重復一次或者多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價於 {1,}。 |
| ? | 重復零次或者一次。例如,"do(es)?" 可以匹配 "do" 、 "does" 中的 "does" 、 "doxy" 中的 "do" 。? 等價於 {0,1}。 |
| {n} | 重復n次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o。 |
| {n,} | 重復n次或多次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價於 'o+'。'o{0,}' 則等價於 'o*'。 |
| {n,m} | 重復n次到m次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價於 'o?'。請注意在逗號和兩個數之間不能有空格。 |
貪婪匹配
貪婪匹配:在滿足匹配時,匹配盡可能長的字符串,默認情況下,采用貪婪匹配
| 正則 | 待匹配字符 | 匹配結果 | 說明 |
| <.*> | <abcdefg>2<hijklmn> | <abcdefg>2<hijklmn> | 默認為貪婪模式,會匹配盡量長的字符串 |
| <.*?> | <abcdefg>2<hijklmn> | <abcdefg> | 加上? 為了將貪婪匹配模式轉為非貪婪匹配模式,會匹配盡量短的字符串 |
幾個常用的非貪婪匹配Pattern
*? 重復任意次,但盡可能少重復 +? 重復1次或更多次,但盡可能少重復 ?? 重復0次或1次,但盡可能少重復 {n,m}? 重復n到m次,但盡可能少重復 {n,}? 重復n次以上,但盡可能少重復
. *?的用法
. 是任意字符 * 是取 0 至 無限長度 ? 是非貪婪模式。 何在一起就是 取盡量少的任意字符,一般不會這么單獨寫,他大多用在: .*?x 就是取前面任意長度的字符,直到一個x出現
re模塊
在python中用來提供正則表達式匹配的模塊就是re模塊
在re模塊中的匹配語法有以下幾種
- re.match:從頭開始匹配,匹配成功返回正則匹配成功的對象,匹配失敗返回None
- re.search:匹配包含的所有,匹配成功返回正則匹配成功的對象,匹配失敗返回None
- re.findall:將所有匹配到的字符以一個列表的形式返回,匹配失敗返回一個空列表
- re.finditer:和findall類似,將匹配到的所有字符作為一個迭代器返回
- re.split:按照能夠匹配的子串將字符串分割后返回列表
- re.sub:匹配字符並替換
- re.compile:編譯正則表達式,生成一個正則表達式( Pattern )對象,供 match() 和 search() 這兩個函數使用。
re.findall函數 *****
- 格式:re.findall(pattern, string, flags=0)
- 參數:
pattern:匹配的正則表達式 string:要匹配的字符串 flags:標志位,用於控制正則表達式的匹配方式,可有可無
標志位常見取值如下:re.I 忽略大小寫 re.L 作本地戶識別 re.M 多行匹配,影響^和$ re.S 使.匹配包括換行符在內的所有字符 re.U 根據Unicode字符集解析字符,影響\w \W \b \B re.X 使我們以更靈活的格式理解正則表達式 - 示例:
ret = re.findall(r'\d+', 'Today454 is1 a 00 day3') # 匹配一位到多位的數字 print(ret) # 結果>>> ['45', '1', '00', '3'] ret = re.findall(r'[a-z]{3}', 'Today is a Good day, Day') # 匹配任意連續三個小寫字母 print(ret) # 結果>>> ['oda', 'ood', 'day'] ret = re.findall(r'[a-z]{3}', 'Today is a Good day, Day', flags=re.I) # 匹配任意連續三個字母,不區分大小寫;flags=re.I表示不區分大小寫 print(ret) # 結果>>> ['Tod', 'Goo', 'day', 'Day']
- findall的優先級查詢:
import re ret = re.findall('www.(baidu|souhu).com', 'www.baidu.com') print(ret) # 結果>>> ['baidu'] 這是因為findall會優先把匹配到的結果,組里的內容返回;如果想要匹配結果,取消權限即可 ret = re.findall('www.(?:baidu|souhu).com', 'www.baidu.com') print(ret) # 結果>>> ['www.baidu.com']
re.search函數 *****
- 格式:re.search(pattern, string, flags=0)
- 參數:
pattern:匹配的正則表達式 string:要匹配的字符串 flags:標志位,用於控制正則表達式的匹配方式 - 示例:
ret = re.search(r'd', 'Today is a Good day, Day') print(ret) # 結果>>> <_sre.SRE_Match object; span=(2, 3), match='d'> print(ret.group()) # 結果>>> d ret = re.search(r'j', 'Today is a Good day, Day') print(ret) # 結果>>> None
re.match函數 ***
- 格式:re.match(pattern, string, flags=0)
- 參數:
pattern:匹配的正則表達式 string:要匹配的字符串 flags:標志位,用於控制正則表達式的匹配方式 - 示例:
ret = re.match(r'www', 'www.baidu.com') print(ret) # 結果>>> <_sre.SRE_Match object; span=(0, 3), match='www'> print(ret.group()) # 結果>>> www ret = re.match(r'www', 'ww.baidu.com') print(ret) # 結果>>> None
re.sub函數 ***
- 格式:re.sub(pattern, repl, string, count=0)
- 參數:
pattern: 正則表達式(規則) repl: 指定的用來替換的字符串 string: 目標字符串 count: 最多替換次數,如果不指定,默認全部替換 - 示例:
ret = re.sub(r'\d', 'H', 'sjkd42jk234523jln5aex8439') print(ret) # 結果>>> sjkdHHjkHHHHHHjlnHaexHHHH ret = re.sub(r'\d', 'H', 'sjkd42jk234523jln5aex8439',count=2) print(ret) # 結果>>> sjkdHHjk234523jln5aex8439 # subn函數:其實和sub一樣,只是返回替換了多少次 ret = re.subn(r'\d', 'H', 'sjkd42jk234523jln5aex8439') print(ret) # 結果>>> ('sjkdHHjkHHHHHHjlnHaexHHHH', 13) ret = re.subn(r'\d', 'H', 'sjkd42jk234523jln5aex8439',count=2) print(ret) # 結果>>> ('sjkdHHjk234523jln5aex8439', 2)
re.split函數 ***
- 格式:re.split(pattern, string, maxsplit=0, flags=0)
- 參數:
pattern:匹配的正則表達式 string:要匹配的字符串 maxsplit : 指定分隔的次數;默認為0,不限制次數 flags:標志位,用於控制正則表達式的匹配方式 - 示例:
ret = re.split(r'\d+', 'www232abcdw3jafe32ad') print(ret) # 結果>>> ['www', 'abcdw', 'jafe', 'ad'] ret = re.split(r'\d+', 'www232abcdw3jafe32ad', maxsplit=2) print(ret) # 結果>>> ['www', 'abcdw', 'jafe32ad']
- split的優先級查詢
ret = re.split('\d+', 'sdjkfl3sdjl5jskd2dsf') print(ret) # 結果>>> ['sdjkfl', 'sdjl', 'jskd', 'dsf'] ret = re.split('(\d+)', 'sdjkfl3sdjl5jskd2dsf') print(ret) # 結果>>> ['sdjkfl', '3', 'sdjl', '5', 'jskd', '2', 'dsf'] ''' 在匹配部分加上()之后所切出的結果是不同的, 沒有()的沒有保留所匹配的項,但是有()的卻能夠保留了匹配的項, 這個在某些需要保留匹配部分的使用過程是非常重要的。 '''
re.compile函數 *****
- 格式:re.compile(pattern)
- 參數:
pattern:要編譯的正則表達式
- 示例:
my_re = re.compile('\d{3}') ret = re.findall(my_re, 'jdla2jd2462jskdf234546') print(ret) # 結果>>> ['246', '234', '546'] ret = re.search(my_re, 'jdla2jd2462jskdf234546').group() print(ret) # 結果>>> 246 ret = re.match(my_re, '43423sjdkfljaj24234').group() print(ret) # 結果>>> 434 # 編譯后的,都可以使用re模塊的其他方法,如:findall、search、match、sub、split等
re.finditer函數 *****
- 格式:re.finditer(pattern, string, flags=0)
- 參數:
pattern:匹配的正則表達式 string:要匹配的字符串 flags:標志位,用於控制正則表達式的匹配方式 - 示例:
ret = re.finditer(r'\d', 'sjkdfl3jskl9ajkl234jdkf75jdslf') for i in ret: print(i.group()) # 結果>>> ''' 3 9 2 3 4 7 5 '''
分組 *****
除了簡單地判斷是否匹配之外,正則表達式還有提取子串的強大功能。用()表示的就是要提取的分組
str3 = "010-52365561" m = re.match(r"(\d{3})-(\d{8})", str3) c = re.match(r"(?P<first>\d{3})-(\d{8})", str3) # ?P<>給組起名 print(m) # 打印結果:<_sre.SRE_Match object; span=(0, 12), match='010-52365561'> print(m.group(0)) #使用序號獲取對應組的信息,group(0)--代表原始的字符串 # 打印結果:010-52365561 print(m.group(1)) # 打印結果:010 print(m.group(2)) # 打印結果:52365561 print(m.groups()) #查看匹配的各組的情況 # 打印結果:('010', '52365561') print(c.group("first")) # 打印結果:010
擴展
匹配標簽
ret = re.search(r'<(?P<tag_name>\w+)>.+</(?P=tag_name)>', '<h1>Hello World</h1>') ''' 還可以在分組中利用?<name>的形式給分組起名字 獲取的匹配結果可以直接用group('名字')拿到對應的值 ''' print(ret.group()) # 結果>>> <h1>Hello World</h1> print(ret.group('tag_name')) # 結果>>> h1 ret = re.search(r'<(\w+)>.+</(\1)>', '<h1>Hello World</h1>') ''' 如果不給組起名字,也可以用\序號來找到對應的組,表示要找的內容和前面的組內容一致 獲取的匹配結果可以直接用group(序號)拿到對應的值 ''' print(ret.group()) # 結果>>> <h1>Hello World</h1> print(ret.group(1)) # 結果>>> h1
匹配整數
ret = re.findall('\d+', "1-2*(60+(-40.35/5)-(-4*3))") print(ret) # 結果>>> ['1', '2', '60', '40', '35', '5', '4', '3'] ret = re.findall('-?\d+\.\d+|(-?\d+)', "1-2*(60+(-40.35/5)-(-4*3))") print(ret) # 結果>>> ['1', '-2', '60', '', '5', '-4', '3'] ret.remove('') print(ret) # 結果>>> ['1', '-2', '60', '5', '-4', '3']
數字匹配
1、 匹配一段文本中的每行的郵箱 http://blog.csdn.net/make164492212/article/details/51656638 2、 匹配一段文本中的每行的時間字符串,比如:‘1990-07-12’; 分別取出1年的12個月(^(0?[1-9]|1[0-2])$)、 一個月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$ 3、 匹配qq號。(騰訊QQ號從10000開始) [1,9][0,9]{4,} 4、 匹配一個浮點數。 ^(-?\d+)(\.\d+)?$ 或者 -?\d+\.?\d* 5、 匹配漢字。 ^[\u4e00-\u9fa5]{0,}$
