python正则表达式
. 除'\n'外的任意一个字符,包含汉字(多行匹配方式下,也能匹配'\n')
* 量词,表示左边的字符可以出现0次或者任意多次
? 量词,表示左边的字符必须出现0次或者1次
+ 量词,表示左边的字符必须出现1次或者更多次
{m} 量词,m是整数。表示左边的字符必须且只能出现m次
{m,n} 量词,m,n都是整数。表示左边的字符必须出现至少m次,最多n次。n也可以不写,表示出现的次数没有上限
\d 一个数字字符,等价于[0-9]
\D 一个非数字字符,等价于[^\d][^0-9]
\s 一个空白字符,如空格,\t,\r,\n等
\S 一个非空白字符
\w 一个单词字符:包括汉字或者大小写英文字母,数字,下划线,或其他语言的文字
\W 一个不是单词字符的字符
| A|B表示能匹配A或能匹配B均算匹配
正则表达式中的特殊字符:
.+?*$[]()^{}\
如果要在正则表达式中,表示这几个字符本身,就应该在前面加上'\'
正则表达式 | 匹配的字符串 |
'a\$b' | 'a$b' |
'a\*b' | 'a*b' |
'a\[\]b' | 'a[]b' |
'a\.*b' |
'ab' 'a.b' 'a..b' ......(ab之间有0个或任意多个.) |
'a\\\\b' |
'a\\b'(注意:此字符串长度为3,中间那个字符是'\', 即r'a\b'。字符串前加r是为了防止转义) |
r'a\\b' | r'a\b'(r'a\b'等价于'a\\b') |
范围符号:[]
用以表示“此处必须出现一个某某范围内的字符”,或者“此处必须出现一个字符,但不可以是某某范围内的字符”
[xxx]的用法,见下表
[a2c] | 匹配'a','2','c'之一 | 's[a2c]k' |
'sak' 's2k' 'sck' |
[a-zA-Z] | 匹配任一英文字母 | 'b[a-z][A-Z]k' |
'bak' 'bUk' ...... |
[\da-z\?] | 匹配一个数字或者小写英文字母或'?' | 'b[\da-z\?]k' |
'b0k' 'bck' 'b?k' ...... |
[^abc] | 匹配一个非'a','b','c'之一的字符 | 'b[^abc]k' |
匹配所有能匹配'b,k'的字符串,除了: 'bak' 'bbk' 'bck' |
[^a-f0-3] | 匹配一个非英文字母'a'到'f',也非数字'0'到'3'的字符 |
匹配汉字:
汉字的unicode编码是:4e00-9fa5(16进制),因此[\u4e00-\u9fa5] 即表示一个汉字
量词的用法:
'.+' | 匹配任意长度不为0且不含'\n'的字符串,'+'表示左边的'.'代表的任意字符出现1次或更多次。不要求出现的字符都必须一样 |
'.*' | 匹配任意不包含'\n'的字符串,包括空串 |
'[\dac]+' | 匹配长度不为0的由数字或者'a','c'构成的串,如'451a','a21c78ca' |
'\w{5}' | 匹配长度为5的由字母或数字或汉字构成的串,如'高大abc','33我a1' |
正则表达式示例:
[1-9]\d* | 正整数 |
-[1-9]\d* | 负整数 |
-?[1-9]\d*|0 | 整数 |
[1-9]\d*|0 | 非负整数 |
-?([1-9\d*\.\d*[1-9]|0\.\d*[0-9]|0]) | 左右两边没有多余0的小数 |
\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* | 邮箱 |
正则表达式的函数
要实用正则表达式,首先需要导入re库
import re
1. re.match()
Signature: re.match(pattern, string, flags=0)
Docstring:
Try to apply the pattern at the start of the string, returning
a match object, or None if no match was found.
File: /usr/lib64/python3.6/re.py
Type: function
flags标志位,用于控制模式串的匹配方式,如:是否区分大小写,多行匹配等等,如re.M | re.| 表示忽略大小写且多行匹配。
import re def match(pattern, string): x = re.match(pattern, string) # re.match() 从头开始匹配 if x != None: print(x.group()) else: print('None') match("a c", "a cdkgh") match("abc", "kabc") match("a\tb*c", "a\tbbcde") match("ab*c", "ac") match("a\d+c", "ac") match("a\d{2}c", "a34c") match("a\d{2,}c", "a3474884c") match(".{2}bc", "cbcd") match(".{2}bc", "bcbcdbc") match("ab.*", "ab") match("ab.*", "abcd") match("\d?b.*", "1bcd") match("\d?b.*", "bbcd") match("a?bc.*", "abbbcd") match("a.b.*", "abcd") match("a.b.*", "aeb") match("a.?b.*", "aebcdf") match("a.+b.*", "aegsfb") match("a.+b.*", "abc") match("a高.+k", "a高大kcd")
2. re.search
Signature: re.search(pattern, string, flags=0)
Docstring:
Scan through string looking for a match to the pattern, returning
a match object, or None if no match was found.
File: /usr/lib64/python3.6/re.py
Type: function
re.search 只能找到第一个匹配的字符串
import re def search(pattern, string): x = re.search(pattern, string) if x != None: print(x.group(), x.span()) else: print("None") search("a.+bc*", "dbaegsfbcef") # aegsfbc (2, 9) search("a.+bc*", "bcdbaegsfbccc") # aegsfbccc (4, 13) search("a.?bc*d", "dabccdc") # abccd (1, 6) search("aa", "baaaa") # aa (1, 3) search("\([1-9]+\)", "ab123(0456)(789)45ab") # (789) (11, 16) search("[1-9]\d+", "ab01203d45") # 1203 (3, 7)
3. re.findall
Signature: re.findall(pattern, string, flags=0)
Docstring:
Return a list of all non-overlapping matches in the string.
If one or more capturing groups are present in the pattern, return
a list of groups; this will be a list of tuples if the pattern
has more than one group.
Empty matches are included in the result.
File: /usr/lib64/python3.6/re.py
Type: function
查找字符串中所有和模式匹配的子串(不重叠),放入列表。一个子串都找不到就返回空列表[]
import re print(re.findall('\d+', "this is 334 what me 774gw")) # ['334', '774'] print(re.findall('[a-zA-Z]+', "A dog has 4 legs.这是true")) # ['A', 'dog', 'has', 'legs', 'true'] print(re.findall('\d+', "this is good.")) # [] print(re.findall('aaa', "baaaa")) # ['aaa']
4. re.finditer
Signature: re.finditer(pattern, string, flags=0)
Docstring:
Return an iterator over all non-overlapping matches in the
string. For each match, the iterator returns a match object.
Empty matches are included in the result.
File: /usr/lib64/python3.6/re.py
Type: function
import re s = '233[32]88ab<433>(21)' m = '\[\d+\]|<\d+>' for x in re.finditer(m ,s): print(x.group(), x.span()) i = 0 for y in re.finditer(m, 'aaaaa'): # 不会被执行 i += 1
5. re.sub
Signature: re.sub(pattern, repl, string, count=0, flags=0)
Docstring:
Return the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in string by the
replacement repl. repl can be either a string or a callable;
if a string, backslash escapes in it are processed. If it is
a callable, it's passed the match object and must return
a replacement string to be used.
File: /usr/lib64/python3.6/re.py
Type: function
import re str = re.sub('\d+', '...', 'abc13de4fg') print(str) # abc...de...fg print(re.sub('\d+', "", "abc13de4fg")) # abcdefg print(re.sub('gone', 'go', "I gone hegone me")) # I go hego me
边界符号
\A 表示字符串的左边界,即要求从此往左边不能有任何字符
\Z 表示字符串的右边界,即要求从此往右边不能有任何字符
^ 与\A同。但多行匹配模式下还可以表示一行文字的左边界
$ 与\Z同。但多行匹配模式下还可以表示一行文字的右边界
边界符号本身不会和任何字符匹配
\b 表示此处应为单词的左边界或者右边界,即不可是单词字符
\B 表示此处不允许是单词的左边界或者右边界,即必须是单词字符
正则表达式的边界符号'\b'是两个字符。但是在python字符中,'\b'和'\t','\n'类似,是一个字符(Backspace)。因此在正则表达式中使用边界符号\b,要写
'\\b'。如果写'\\\\b',则连续的两个'\'被看作一个普通的'\',不会和后面的'b'一起被当作字符组合,变成边界符号'\b'
import re def search(pattern, string): x = re.search(pattern, string) if x != None: print(x.group(), x.span()) else: print("None") pt = 'ka\\b.*' # 表示单词a的右边不能是字符 search(pt, "ka") # ka (0, 2) search(pt, "kax") # None search(pt, "ka?d") # ka?d (0, 4) pt = '.*\\bka\\b' search(pt, "ka") # ka (0, 2) search(pt, "ska?") # None search(pt, "b?ka?") # b?ka (0, 4) m = r"\bA.*N\b T" search(m, "Ass$NC TK") # None search(m, "this Ass$N TK") # Ass$N T m = "\BA.*N\B\w T" search(m, "this Ass$N TK") # None search(m, "thisAss$NM TK") # Ass$NM T search(m, "Ass$NM TK") # None search(m, "xAss$NM TK") # Ass$NM T pt = '\\b高兴' search(pt, "我高兴") # None search(pt, "我 高兴") # 高兴
分组
括号中的表达式是一个分组。多个分组按左括号从左到右从1开始依次排序
import re x = re.search('[a-z]+(\d+)[a-z]+', "ab 123d hello553world47") print(x.group(1)) # group(0)、group()返回整个匹配,group(1)返回第一个分组,groups返回从1开始匹配的分组 m = "(((ab*)c)d)e" r = re.match(m, "abcdefg") print(r.group(0)) # For 0 returns the entire match. abcde print(r.group(1)) # abcd print(r.group(2)) # abc print(r.group(3)) # ab print(r.groups()) # Return a tuple containing all the subgroups of the match, from 1. # ('abcd', 'abc', 'ab') m = "(ab*)(c(d))e" r = re.match(m, "abcdefg") print(r.groups()) # ('ab', 'cd', 'd') print(r.group(0)) # abcde print(r.group(1)) # ab print(r.group(2)) # cd print(r.group(3)) # d
在分组的右边可以通过分组的编号引用该分组所匹配的子串
import re m = r'(((ab*)c)d)e\3' r = re.match(m, "abbbcdeabbbkfg") print(r.group(3)) # abbb print(r.group()) # abbbcdeabbb
pt = 'a(.)\\1*b' # 等价于pt = r'a(.)\1*b'
print(re.search(pt, 'kacccccb').group()) # acccccb
print(re.search(pt, 'kaxxxxb').group()) # axxxxb
print(re.search(pt, 'kaxb').group()) # axb
x = re.search(pt, 'kaxyb')
if x != None:
print(x.group())
分组作为一个整体,后面可以跟量词
import re m = "(((ab*)+c)d)e" r = re.match(m, "ababcdefg") # ('ababcd', 'ababc', 'ab') print(r.groups()) r = re.match(m, "abacdefg") # ('abacd', 'abac', 'a') 不要求分组的多次出现,必须匹配相同字符串 print(r.groups())
在正则表达式中没有分组时,re.findall返回所有匹配子串构成的列表。
有且只有一个分组时,re.findall返回的是一个子串的列表,每个元素是一个匹配子串中分组对应的内容
import re m = '[a-z]+(\d+)[a-z]+' x = re.findall(m, "13 bc12de ab11 cd320ef") print(x) #['12', '320']
在正则表达式中有超过一个分组时,re.findall返回的是一个元组的列表,每个元组对应于一个匹配的子串,元组里的元素,依次是1号分组、
2号分组、3号分组......匹配的内容
import re m = '(\w+) (\w+)' r = re.match(m, 'hello world') print(r.groups()) print(r.group(1)) print(r.group(2)) r = re.findall(m, "hello world, this is very good") print(r)
|的用法
‘|’表示’或‘,如果没有放在“()”中,则起作用范围是直到整个正则表达式开头或结尾或另一个"|"
从左到右短路匹配(匹配上一个后就不计算是否还能匹配后面的)
import re pt = "\d+\.\d+|\d+" # 匹配整数或者小数 print(re.findall(pt, "12.34 this is 125")) # ['12.34', '125'] pt = "aa|aab" print(re.findall(pt, "aabcdeaa12aab")) # ['aa', 'aa', 'aa']
'|'也可以用于分组中,起作用范围仅限于分组内
import re m = "(((ab*)+c|12)d)e" print(re.findall(m, 'ababcdefgKK12deKK')) # [('ababcd', 'ababc', 'ab'), ('12d', '12', '')] for x in re.finditer(m, 'ababcdefgKK12deKK'): print(x.groups()) # ('ababcd', 'ababc', 'ab') # ('12d', '12', None) m = '\[(\d+)\]|<(\d+)>' for x in re.finditer(m, '233[32]88ab<443>'): print(x.group(), x.groups()) # [32] ('32', None) # <443> (None, '443')
贪婪模式和懒惰模式
贪婪模式:量词+,*,?,{m,n}默认匹配尽可能长的子串
import re
print(re.match("ab*", "abbbbk").group()) # abbbb
print(re.findall("<h3>(.*)</h3>", "<h3>abd</h3><h3>bcd</h3>")) # ['abd</h3><h3>bcd']
print(re.findall('\(.+\)', "A dog has(have a).这(哈哈)true()me")) # ['(have a).这(哈哈)true()']
懒惰模式:在量词+,*,?,{m,n}后面加'?'则匹配尽可能短的字符串
import re m = "a.*?b" # .*?表示.*采用懒惰匹配 for k in re.finditer(m, "aabab"): print(k.group(), end=" ") # aab ab m = "<h3>.*?</h3>" a = re.match(m, "<h3>abd</h3><h3>bcd</h3>") print(a.group()) # <h3>abd</h3> m = "<h3>.*?[M|K]</h3>" a = re.match(m, "<h3>abd</h3><h3>bcK</h3>") # <h3>abd</h3><h3>bcK</h3> print(a.group())
print(re.findall('\d+?', "this is 334 what me 774gw"))
# [3, 3, 4, 7, 7, 4]
print(re.findall('[a-zA-Z]+?', "A dog has 4 legs.这是true"))
# ['A', 'd', 'o', 'g', 'h', 'a', 's', 'l', 'e', 'g', 's', 't', 'r', 'u', 'e']
print(re.findall('\(.*?\)', "A dog has(have).这(哈哈)true()me"))
# ['(have)', '(哈哈)', '()']
匹配对象的函数
string:匹配时使用的母串
lastindex:最后一个被匹配的分组的编号(不是最大编号)。如果没有被匹配的分组,将为None
group([n1,n2,...]):
- 获得一个或多个分组匹配的字符串;指定多个参数时将以元组形式返回。n1,n2,...可以使用编号也可以使用名字
- 编号0代表整个匹配的子串(与模式里的"()"无关)
- group()等价于group(0)
- 没有匹配字符串的组返回None
- 匹配了多次的组返回最后一次匹配的子串
groups([default]):
以元组形式返回全部分组匹配的字符串。相当于调用group(1,2,...last)。
defalut表示没有匹配字符串的组以这个值替代,默认为None。
start([group]):
返回指定的组匹配的子串在string中的起始位置。group默认值为0
end([group]):
返回指定的组匹配的子串在string中的结束位置(子串最后一个字符的位置+1)。group默认值为0
span([group]):
返回(start(group), end(group))
group可以是组编号,也可以是组名字,缺省为0
import re m = re.match(r'(\w+) (\w+)(.)', 'hello world!ss') print(m.string) # 匹配的字符串是'hello world!ss' print(m.lastindex) # 3 print(m.group(0, 1, 2, 3)) # ('hello world!', 'hello', 'world', '!') print(m.groups()) # ('hello', 'world', '!') print(m.start(2)) # 6 print(m.end(2)) # 11 print(m.span(2)) # (6, 11)