和其他编程语言一样,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'))

前面提到无法像 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岁

评论




正在载入...
PoweredHexo
HostedAliyun
DNSAliyun
ThemeVolantis
UV
PV
BY-NC-SA 4.0