Python 学习笔记之——正则表达式
0. 常用匹配规则
^
匹配字符串的开头$
匹配字符串的结尾[...]
匹配一组字符,比如[abc]
表示匹配小写字母a
或者b
或者c
,[a-z]
表示匹配所有的小写字母,[0-3]
表示匹配数字0,1,2,3
[^...]
匹配不在[]
中的字符.
匹配除了换行符以外的任意字符,当匹配模式指定为re.S
时则可以匹配任意字符*
匹配零个或者多个表达式+
匹配一个或者多个表达式?
匹配零个或者一个前面的表达式,非贪婪方式,也就是尽可能少地匹配{n}
精确匹配 n 个前面的表达式,比如s{2}
必须匹配字符串中连续的两个s
{n,m}
匹配 n 到 m 个前面的表达式,贪婪方式,也即是尽可能多地匹配。比如s{1,3}
可以匹配 1 到 3 个s
,但是如果有 3 个就全部匹配{n,}
匹配至少 n 个前面的表达式,比如s{1,}
等价于s+
,s{0,}
等价于s*
a|b
匹配a
或者b
\d
匹配任意数字,也即 0-9\D
匹配任意非数字\w
匹配字母数字和下划线\W
匹配非字母数字和下划线\s
匹配任意空白字符,也即 Tab\t
、换行符\n
、回车符\r
和 换页符\f
\S
匹配任意非空白字符\A
匹配字符串开始\Z
匹配字符串结尾
1. re.match
函数原型:
re.match(pattern, string, flags=0)
re.match 尝试从待匹配字符串的第一个字符开始匹配,如果匹配不成功就返回 None。
- pattern 匹配的正则表达式
- string 待匹配的字符串
- flag=0 指定匹配模式,比如
re.I
使得匹配对大小写不敏感,re.S
使得.
匹配符可以匹配包含换行符在内的所有字符
content = 'I am seniusen!'
res = re.match('I am.*', content)
print(res.group()) # I am seniusen!
res = re.match('Q am.*', content)
print(res) # None
指定匹配模式
content = 'I AM SENIUSEN!'
res = re.match('i am seniusen', content)
print(res) # None
res = re.match('i am seniusen!', content, re.I)
print(res.group()) # I AM SENIUSEN!
还可以用 |
将两个匹配模式组合起来一起使用
content = '''I AM
SENIUSEN!'''
res = re.match('i am.*', content, re.I)
print(res.group()) # I AM
res = re.match('i am.*', content, re.I|re.S)
print(res.group())
# I AM
# SENIUSEN!
用括号可以获取匹配到的内容,res.group(1)
代表第一个括号内匹配的内容,res.group(2)
代表第二个括号内匹配的内容
content = 'My name is seniusen, I was born in 1997, Henan, China.'
res = re.match('My.*?(\d+).*', content)
print(res.group())
# My name is seniusen, I was born in 1997, Henan, China.
print(res.group(1)) # 1997
res = re.match('My.*?(\d{1,3}).*', content)
print(res.group(1)) # 199
上面 .*
可以匹配任意的非换行字符,?
代表非贪婪模式,也就是一旦遇到了数字,就交给括号里面的 \d+
来匹配,所以得到了 1997
。
content = 'My name is seniusen, I was born in 1997, Henan, China.'
res = re.match('My.*(\d+).*', content)
print(res.group(1)) # 7
res = re.match('My.*(\d{1,3}).*', content)
print(res.group(1)) # 7
而如果去掉了 ?
,则代表是贪婪模式,那么 .*
会一直匹配到 199
才结束,只留给 \d+
匹配一个数字 7
。
如果涉及到一些特殊字符,比如 *
和 $
,它们在正则表达式匹配中有一些特定含义,那么就不能直接来匹配了,需要使用转义字符 \
。
content = 'The total cost is $5.00*'
res = re.match('The total cost is $5.00*', content)
print(res) # None,$ 被当作了字符串结尾,无法匹配
res = re.match('The total cost is \$5.00\*', content)
print(res.group()) # The total cost is $5.00*
2. re.search
函数原型:
re.search(pattern, string, flags=0)
其参数和 re.match 一样,但 re.search 尝试搜索整个字符串,然后返回第一个成功的匹配。
content = 'I am seniusen!'
res = re.match('am.*', content)
print(res) # None
res = re.search('am.*', content)
print(res.group(), res.span())
# am seniusen! (2, 14)
# res.span() 返回匹配的位置
3. re.findall
函数原型:
re.findall(pattern, string, flags=0)
re.findall 尝试从待匹配字符串找出所有的匹配项,然后返回一个字符串列表。
content = 'I am seniusen, 3 years ago I was 20 years old!'
res = re.findall('sen', content)
print(res) # ['sen', 'sen']
res = re.findall('\d+', content)
print(res) # ['3', '20']
4. re.sub
函数原型:
re.sub(pattern, repl, string, count=0, flags=0)
re.sub 尝试从待匹配字符串中找出所有的匹配并进行替换。
- repl 替换的字符串,也可以是一个函数
- count=0 替换的最大次数,默认为零表示替换所有的匹配
content = 'I am seniusen, 3 years ago I was 20 years old!'
res = re.sub('\d+', 'xxx', content)
print(res)
# I am seniusen, xxx years ago I was xxx years old!
res = re.sub('(\d+)\s(.*?)s', r'\1x \2s', content)
print(res)
# I am seniusen, 3x years ago I was 20x years old!
res = re.sub('(\d+)\s(.*?)s', r'\1x \2s', content, 1)
print(res)
# I am seniusen, 3x years ago I was 20 years old!
上面第一次是将字符串中所有的数字替换为 xxx
,第二次是在数字后添加一个 x
。其中 \1
代表前面第一个括号中匹配的内容,而 \2
代表前面第二个括号中匹配的内容,注意这里避免转义要添加上 r
。第三次我们则设置只能替换一次。
def num2word(matched):
word = {'3': 'three', '20': 'twenty'}
return word[matched.group('num')]
content = 'I am seniusen, 3 years ago I was 20 years old!'
res = re.sub('(?P<num>\d+)', num2word, content)
print(res)
# I am seniusen, three years ago I was twenty years old!
上面的 repl 参数是一个函数,表示将匹配到的数字转化为其对应的英文单词。其中 ?P<num>
表示给匹配到的内容进行一个分组,然后通过 matched.group('num')
就可以很方便地取出这个匹配结果。上面的代码和下面这段等价。
def num2word(matched):
word = {'3': 'three', '20': 'twenty'}
return word[matched.group()]
content = 'I am seniusen, 3 years ago I was 20 years old!'
res = re.sub('\d+', num2word, content)
print(res)
5. re.compile
函数原型:
re.compile(pattern[, flags])
re.compile 用于构建一个正则表达式对象,便于重复使用。
content = 'I am seniusen, 3 years ago I was 20 years old!'
pattern = re.compile('\d+') # 匹配至少一个数字
res = pattern.match(content)
print(res) # None 从头开始,无法匹配数字
res = pattern.search(content)
print(res.group()) # 3 匹配第一个数字
res = pattern.findall(content)
print(res) # ['3', '20'] 匹配到所有的数字
res = pattern.findall(content, 0, 16)
print(res) # ['3'] 限制在第 1 到第 16 个字符之间查找
获取更多精彩,请关注「seniusen」!