和其他编程语言一样,Python 正则表达式也是为了匹配字符串。Python 的正则表达式是由 re 标准库提供的,拥有了基本所有的表达式。
方法 | 描述 |
---|---|
re.compile(pattern, flags=0) | 把正则表达式编译成一个对象(已弃用) |
re.match(pattern, string, flags=0) | 匹配字符串开始,如果不匹配返回None |
re.search(pattern, string, flags=0) | 扫描字符串,寻找匹配,如果符合返回一个匹配对象,并终止匹配,反之返回None。类似grep |
re.split(pattern, string, maxsplit=0, flags=0) | 以匹配模式作为分隔符,切分字符串为列表 |
re.findall(pattern, string, flags=0) | 以列表形式返回所有匹配的字符串 |
re.finditer(pattern, string, flags=0) | 以迭代器形式返回所有匹配的字符串 |
re.sub(pattern, repl, string, count=0, flags=0) | 字符串替换,repl替换匹配的字符串,repl可以是一个函数 |
re.match()
import re
text = "This is a sentence"
pattern = re.match('This', text)
print(pattern)
print(pattern.group())
# 输出结果
<_sre.SRE_Match object; span=(0, 4), match='This'>
This
我在尝试的过程中,发现不能像 shell 一样匹配中间段的字符串,这是因为 python 的正则匹配是从左到右匹配的,不会截取中间段的字符串。
忽略大小写(re.I)
import re
text = "This is a sentence"
pattern = re.match('this', text, re.I)
print(pattern.group())
匹配所有字符(re.S)
import re
text = """This is
a
sentence
"""
pattern = re.match('\w.*', text, re.S)
print(pattern.group())
模糊匹配
在 shell 中模糊匹配有 ?/*/[0-9]/[a-z|A-Z]...
,Python 中有自己独有的规则,如下表:
字符 | 描述 |
---|---|
. | 任意单个字符,除了\n |
[ ] | 匹配括号中任意一个字符,并且特殊符号在[ ]内也会被作为普通字符进行匹配 |
[.-.] | 匹配括号中范围内字符[0-9],[a-z],[A-Z] |
[^.] | 匹配出括号内字符之外的所有字符 |
\d | 匹配数字,等效[0-9] |
\D | 匹配非数字字符,等效[^0-9] |
\s | 匹配单个空白字符,等效[\t\r\n\f\v] |
\S | 匹配非空白字符,等效[^\t\r\n\f\v] |
\w | 匹配字母、数字、下划线,等效[a-zA-Z0-9_] |
\W | 匹配非字母、非数字、非下划线,等效[^a-zA-z0-9_] |
以上模糊匹配的代表字符都将匹配的是单个字符
import re
text = "123\\abc"
pattern = re.match('\d\d\d\\\\[a-z][a-z][a-z]', text)
print(pattern.group())
以上的例子可以看到匹配 \\
用了 \\\\
,和 shell 中一样 \
的作用是转义,理解转义的情况下就可以看明白了。在匹配中可以使用 r
将本身具有特殊意义的字符自动转义
import re
text = "123\\abc"
pattern = re.match(r'\d\d\d\\[a-z][a-z][a-z]', text)
print(pattern.group())
模糊+多字符匹配
上面提到模糊匹配都是匹配的单个字符,如果要匹配一直重复加也没有很简介高效。匹配多个字符 python 中也是有解决办法的。
字符 | 描述 |
---|---|
* | 匹配前面正则表达式的0次或无数次 |
+ | 匹配前面正则表达式的1次或多次 |
? | 匹配前面正则表达式的0次或1次 |
{n} | 匹配括号前字符的n次 |
{n,} | 匹配括号前字符至少n次 |
{n,m} | 匹配括号前字符至少n次,最多m次 |
示例:尝试 print()
以下变量,看看什么效果
import re
text = "123\\abc"
pattern = re.match('.*', text) # .*表示任意字符匹配
pattern1 = re.match('\d+', text)
pattern2 = re.match('\d?', text)
pattern3 = re.match('\d{3}', text)
pattern4 = re.match('\d{1,}', text)
pattern5 = re.match('\d{1,3}', text)
边界匹配
以…开头,以…结尾等的效果
字符 | 描述 |
---|---|
^ | 匹配以什么开头 |
$ | 匹配以什么结尾 |
\b | 匹配单词边界(使用较少,以后再说) |
\B | 匹配非单词边界(使用较少,以后再说) |
示例:
import re
email = input("请输入你的注册邮箱:").strip()
result = re.match("^\w+@\w+\.[a-z]+$", email)
if result:
print("邮箱格式正确!")
else:
print("邮箱格式错误!")
分组匹配
字符 | 描述 |
---|---|
(a|1) | 匹配竖杠两边任一正则表达式 |
() | 匹配小括号中正则表达式,在一行正则中用来分组 使用\n反向引用,n代表数字,从1开始编号,表示引用第几组匹配的内容 |
(?P<name>re) | 分组别名,name是分组名 |
(?P=name) | 引用分组别名 |
示例:邮箱限制163、qq、gmail
import re
email = input("请输入你的注册邮箱:").strip()
result = re.match("^\w+@(qq|gmail|163)\.[a-z]+$", email)
if result:
print("邮箱格式正确!")
else:
print("邮箱格式错误!")
分组示例:
import re
email = input("请输入你的注册邮箱:").strip()
result = re.match(r"^(\w+)@(\1)\.([a-z]+$)", email)
if result:
print("邮箱格式正确!")
else:
print("邮箱格式错误!")
print(result.group(1))
print(result.group(2))
print(result.group(3))
以上代码中 r"^(\w+)@(\1)\.([a-z]+$)"
使用了反向引用,需要注意的是,这里的 \1
引用的是 (\w+)
匹配到的结果,也就是如果你输入的邮箱是 123@qq.com
,这样的格式会被认为是错误的,因为 1 的位置匹配到的是 123,而 \1
的位置是 qq,并没有匹配到 123,会被认为结果不正确;如果输入的是 123@123.com
,则匹配结果是没问题的。
分组别名示例:
import re
email = input("请输入你的注册邮箱:").strip()
result = re.match(r"(?P<abc>^\w+)@(?P=abc)\.([a-z]+$)", email)
if not result:
print("邮箱格式错误!")
else:
print("邮箱格式正确!")
print(result.group('abc'))
re.search()
前面提到无法像 shell 中 grep 那样检索全文进行匹配,而 re.search()
就是这个作用
import re
text = "我今年60岁"
pattern = re.search("\d+", text)
print(pattern.group())
re.split()
以匹配模式作为分隔符,切分字符串为列表,类似 awk
的 -F
import re
text = "我今年,60岁"
pattern = re.split(",", text)
print(pattern)
re.findall()
以列表形式返回所有匹配的字符串
import re
text = "我今年,60岁"
pattern = re.findall("\d+", text)
print(pattern)
# 输出结果
['60']
re.finditer() 与 findall() 同理。
re.sub()
字符串替换,repl替换匹配的字符串,repl可以是一个函数
import re
text = "我今年,60岁"
pattern = re.sub("\d+", "27", text)
print(pattern)
# 输出结果
我今年,27岁