一.re模块简介
这个模块提供了与 Perl 语言类似的正则表达式匹配操作。
模式和被搜索的字符串既可以是 Unicode 字符串 (str) ,也可以是8位字节串 (bytes)。 但是,Unicode 字符串与8位字节串不能混用:也就是说,你不能用一个字节串模式去匹配 Unicode 字符串,反之亦然;类似地,当进行替换操作时,替换字符串的类型也必须与所用的模式和搜索字符串的类型一致。
正则表达式使用反斜杠('')来表示特殊形式,或者把特殊字符转义成普通字符。 而反斜杠在普通的 Python 字符串里也有相同的作用,所以就产生了冲突。比如说,要匹配一个字面上的反斜杠,正则表达式模式不得不写成 '\\',因为正则表达式里匹配一个反斜杠必须是 \ ,而每个反斜杠在普通的 Python 字符串里都要写成 \ 。
解决办法是对于正则表达式样式使用 Python 的原始字符串表示法;在带有 'r' 前缀的字符串字面值中,反斜杠不必做任何特殊处理。 因此 r"\n" 表示包含 '' 和 'n' 两个字符的字符串,而 "\n" 则表示只包含一个换行符的字符串。 样式在 Python 代码中通常都会使用这种原始字符串表示法来表示。
绝大部分正则表达式操作都提供为模块函数和方法,在 编译正则表达式. 这些函数是一个捷径,不需要先编译一个正则对象,但是损失了一些优化参数。
第三方模块 regex , 提供了与标准库 re
模块兼容的API接口, 同时还提供了额外的功能和更全面的Unicode支持。
1.1 匹配符
python的匹配符比较多,下面罗列一些常用的。
常用配符 | 概述 |
---|---|
. | (点) 在默认模式,匹配除了换行的任意字符。如果指定了标签 DOTALL ,它将匹配包括换行符的任意字符。 |
^ | (插入符号) 匹配字符串的开头, 并且在 MULTILINE 模式也匹配换行后的首个符号 |
$ | 匹配字符串尾或者在字符串尾的换行符的前一个字符,在 MULTILINE 模式下也会匹配换行符之前的文本。 |
* | 对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。 ab* 会匹配 'a','ab',或者 'a' 后面跟随任意个 'b'。 |
+ | 对它前面的正则式匹配1到任意次重复。 ab+ 会匹配 'a' 后面跟随1个以上到任意个 'b',它不会匹配 'a'。 |
? | 对它前面的正则式匹配0到1次重复。 ab? 会匹配 'a' 或者 'ab'。 |
\ | 转义特殊字符(允许你匹配 '*', '?', 或者此类其他),或者表示一个特殊序列;特殊序列之后进行讨论。 |
| | A|B, 匹配A或者B,A成功了,就不会匹配B |
[] | 用于表示一个字符集合,比如 [amk] 匹配 'a', 'm', 或者 'k' |
1.1.1 字符集合
字符 | 匹配的字符 |
---|---|
\number | 匹配数字代表的组合。 |
\A | 只匹配字符串开始 |
\b | 匹配空字符串,但只在单词开始或结尾的位置。 |
\B | 匹配空字符串,但 不 能在词的开头或者结尾 |
\d | 匹配任何十进制数,就是 [0-9] |
\D | 匹配非[0-9]的数字,与\d 相反 |
\s | 匹配ASCII中的空白字符,就是 [ \t\n\r\f\v] 。 |
\S | 匹配任何不是空白字符的字符,与\s相反 |
\w | 匹配ASCII字符中的数字和字母和下划线,就是 [a-zA-Z0-9_] 。 |
\W | 匹配任何不是单词字符的字符,与\w相反 |
\Z | 只匹配字符串尾。 |
1.1.2 重复次数
贪婪模式会获取尽可能多的字符,而非贪婪模式会获取尽可能少的字符。
贪婪 | 非贪婪 | 描述 |
---|---|---|
* | *? | 零次或多次 |
? | ?? | 零次或一次 |
+ | +? | 一次或多次 |
{m} | {m}? | 正好m次,贪婪与非贪婪一样的,比如, a{6} 将匹配6个 'a' |
{m,} | {m,}? | 至少m次, 比如 a{4,}b 将匹配 'aaaab' 或者1000个 'a' 尾随一个 'b',但不能匹配 'aaab' |
{m, n} | {m, n}? | 最少m最多n次,比如,对于 'aaaaaa', a{3,5} 匹配 5个 'a' ,而 a{3,5}? 只匹配3个 'a' |
1.1.3 组合匹配符
组合匹配是多个匹配规则配合起来。
例如,我要匹配身份证号码
^[1-9]\d{13,16}[0-9x]$
上面这个代码有3个部分
- ^[1-9] 开头是1-9的一个数字
- \d{13,16} 中间是最少13个数字,最多16个数字
- [0-9xX]$ 结尾是0-9、x或者X中的一个
组合匹配符 | 概述 |
---|---|
(...) | (组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用 \number 转义序列进行再次匹配,之后进行详细说明。要匹配字符 '(' 或者 ')', 用 ( 或 ), 或者把它们包含在字符集合里: [(], [)]. |
(?…) | 这是个扩展标记法 (一个 '?' 跟随 '(' 并无含义)。 '?' 后面的第一个字符决定了这个构建采用什么样的语法。 |
(?aiLmsux) | ( 'a', 'i', 'L', 'm', 's', 'u', 'x' 中的一个或多个) 这个组合匹配一个空字符串;这 |
(?:…) | 正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串 不能 在执行匹配后被获取或是之后在模式中被引用。 |
(?#…) | 注释;里面的内容会被忽略。 |
(?=…) | 匹配 … 的内容,但是并不消费样式的内容。这个叫做 lookahead assertion。比如, Isaac (?=Asimov) 匹配 'Isaac ' 只有在后面是 'Asimov' 的时候。 |
(?!…) | 匹配 … 不符合的情况。这个叫 negative lookahead assertion (前视取反)。比如说, Isaac (?!Asimov) 只有后面 不 是 'Asimov' 的时候才匹配 'Isaac ' 。 |
(?<=…) | 匹配字符串的当前位置,它的前面匹配 … 的内容到当前位置 |
(?<!…) | 匹配当前位置之前不是 … 的样式。 |
(?(id/name)yes-pattern|no-pattern) | 如果给定的 id 或 name 存在,将会尝试匹配 yes-pattern ,否则就尝试匹配 no-pattern,no-pattern 可选,也可以被忽略。 |
二.模块内容
模块定义了几个函数,常量,和一个例外。有些函数是编译后的正则表达式方法的简化版本(少了一些特性)。绝大部分重要的应用,总是会先将正则表达式编译,之后在进行操作。
2.1 常用函数
函数 | 概述 |
---|---|
re.compile(pattern, flags=0) | 将一个正则表达式模式编译成一个正则表达式对象,可以使用它的match()、search()和其他方法进行匹配,如果需要多次使用这个正则表达式的话,使用 re.compile() 和保存这个正则对象以便复用,可以让程序更加高效。 |
re.I/re.IGNORECASE | 进行忽略大小写匹配;表达式如 [A-Z] 也会匹配小写字符。Unicode匹配(比如 Ü 匹配 ü)同样有用,除非设置了 re.ASCII 标记来禁用非ASCII匹配。当前语言区域不会改变这个标记,除非设置了 re.LOCALE 标记。这个相当于内联标记 |
re.L/re.LOCALE | 由当前语言区域决定 \w, \W, \b, \B 和大小写敏感匹配。这个标记只能对byte样式有效。这个标记不推荐使用,因为语言区域机制很不可靠,它一次只能处理一个 “习惯”,而且只对8位字节有效。 |
re.M/re.MULTILINE | 设置以后,样式字符 '^' 匹配字符串的开始,和每一行的开始(换行符后面紧跟的符号);样式字符 '' 匹配字符串尾。对应内联标记 (?m) 。 |
re.S/re.DOTALL | 让 '.' 特殊字符匹配任何字符,包括换行符;如果没有这个标记,'.' 就匹配 除了 换行符的其他任意字符。 |
re.X/re.VERBOSE | 这个标记允许你编写更具可读性更友好的正则表达式。通过分段和添加注释。空白符号会被忽略,除非在一个字符集合当中或者由反斜杠转义,或者在 *?, (?: or (?P<…> 分组之内。当一个行内有 # 不在字符集和转义序列,那么它之后的所有字符都是注释。 |
re.search(pattern, string, flags=0) | 扫描整个 字符串 找到匹配样式的第一个位置,并返回一个相应的 匹配对象。如果没有匹配,就返回一个 None ; 注意这和找到一个零长度匹配是不同的。 |
re.match(pattern, string, flags=0) | 如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的 匹配对象 。 如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。 注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的开始位置,而不匹配每行开始。 如果你想定位 string 的任何位置,使用 search() 来替代(也可参考 search() vs. match() ) |
re.fullmatch(pattern, string, flags=0) | 如果整个 string 匹配到正则表达式样式,就返回一个相应的 匹配对象 。 否则就返回一个 None ;注意这跟零长度匹配是不同的 |
re.split(pattern, string, maxsplit=0, flags=0) | 用 pattern 分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素 |
re.findall(pattern, string, flags=0) | 对 string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。 |
re.escape(pattern) | 转义除ASCII字母、数字和'_'之外的模式中的所有字符。如果您想要匹配任意可能包含正则表达式元字符的字面值字符串,这是非常有用的 |
re.purge() | 清除正则表达式缓存。 |
2.2 异常
exception re.error(msg, pattern=None, pos=None)
raise 一个例外。当传递到函数的字符串不是一个有效正则表达式的时候(比如,包含一个不匹配的括号)或者其他错误在编译时或匹配时产生。如果字符串不包含样式匹配,是不会被视为错误的。
属性 | |
---|---|
msg | 未格式化的错误消息。 |
pattern | 正则表达式样式 |
pos | 编译失败的 pattern 的位置索引(可以是 None )。 |
lineno | 对应 pos (可以是 None) 的行号。 |
colno | 对应 pos (可以是 None) 的列号。 |
2.3 匹配对象
re.search、re.match、re.fullmatch、re.finditer 都支持匹配对象
匹配对象支持以下方法和属性
属性 | 描述 |
---|---|
match.expand(template) | 返回通过在模板字符串模板上执行反斜杠替换获得的字符串,就像sub()方法那样。转义(例如\n)被转换为适当的字符,数字反向引用(\1,\2)和命名反向引用(\g<1>, \g)被相应组的内容替换。 |
match.group([group1, ...]) | 返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串,如果有多个参数,结果就是一个元组(每个参数对应一个项),如果没有参数,组1默认到0(整个匹配都被返回)。 |
match.getitem(g) | 这个等价于 m.group(g)。这允许更方便的引用一个匹配 |
match.groups(default=None) | 返回一个元组,包含所有匹配的子组,在样式中出现的从1到任意多的组合。 default 参数用于不参与匹配的情况,默认为 None。 |
match.groupdict(default=None) | 返回一个字典,包含了所有的 命名 子组。key就是组名。 default 参数用于不参与匹配的组合;默认为 None |
match.start([group]) | 返回 group 匹配到的字串的开始标号 |
match.end([group]) | 返回 group 匹配到的字串的结束标号 |
match.span([group]) | 对于一个匹配 m , 返回一个二元组 (m.start(group), m.end(group)) |
match.pos | pos的值,传递给regex对象的search()或match()方法。这是RE引擎不能超越的字符串索引。 |
match.endpos | endpos的值,传递给regex对象的search()或match()方法。这是RE引擎不能超越的字符串索引。 |
match.lastindex | 捕获组的最后一个匹配的整数索引值,或者 None 如果没有匹配产生的话。 |
match.lastgroup | 最后一个匹配的命名组名字,或者 None 如果没有产生匹配的话。 |
match.re | match()或search()方法产生这个匹配实例的正则表达式对象 |
match.string | 传递给match()或search()的字符串 |
三.正则案例
3.1 re.search
语法:
re.search(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等 re.I (ignore case), re.M (multi-line), re.S (dot matches all), and re.X (verbose) |
扫描整个 字符串 找到匹配样式的第一个位置,并返回一个相应的 匹配对象。如果没有匹配,就返回一个 None ; 注意这和找到一个零长度匹配是不同的。
代码:
import re
# 匹配是否存在
content1 = "I love python,I'm studying python!"
result1 = re.search('python', content1)
# 如果匹配成功输出结果,否则输出"匹配失败"
if result1:
print(result1.group())
else:
print("匹配失败")
content2 = "I love python,I'm studying python!"
result2 = re.search('test', content2)
# 如果匹配成功输出结果,否则输出"匹配失败"
if result2:
print(result2.group())
else:
print("匹配失败")
print("\n")
# 匹配数字
content = 'Hello 123456789 Word_This is just a test 666 Test'
result = re.search('(\d+).*?(\d+).*', content)
print(result)
print(result.group()) # print(result.group(0)) 同样效果字符串
print(result.groups())
print(result.group(1))
print(result.group(2))
print(result.start())
print(result.end())
print(result.span())
print("\n")
# 匹配前3个单词
content = 'Hello 123456789 Word_This is just a test 666 Test'
result = re.search('([a-zA-Z]+).*?([a-zA-Z]+).*?([a-zA-Z]+)', content)
# 输出匹配的结果,是一串字符
print(result)
print(result.string)
# 输出group相关
print(result.group()) # print(result.group(0)) 同样效果字符串
print(result.groups())
print(result.group(1))
print(result.group(2))
print(result.group(3))
# 输出匹配的规则
print(result.re)
# 输出匹配开始和结尾 开始匹配的字符是 start+1
print(result.start())
print(result.end())
print(result.span())
# 输出字符的开始位置和结束位置
print(result.pos)
print(result.endpos)
# 输出组最后的标记
print(result.lastindex)
print(result.lastgroup)
测试记录:
E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/re_test1.py
python
匹配失败
<_sre.SRE_Match object; span=(6, 49), match='123456789 Word_This is just a test 666 Test'>
123456789 Word_This is just a test 666 Test
('123456789', '666')
123456789
666
6
49
(6, 49)
<_sre.SRE_Match object; span=(0, 25), match='Hello 123456789 Word_This'>
Hello 123456789 Word_This is just a test 666 Test
Hello 123456789 Word_This
('Hello', 'Word', 'This')
Hello 123456789 Word_This
Hello
Word
This
re.compile('([a-zA-Z]+).*?([a-zA-Z]+).*?([a-zA-Z]+)')
0
25
(0, 25)
0
49
3
None
Process finished with exit code 0
3.2 re.match
语法:
re.match(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等 re.I (ignore case), re.M (multi-line), re.S (dot matches all), and re.X (verbose) |
如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的 匹配对象 。 如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。
注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的开始位置,而不匹配每行开始。
如果你想定位 string 的任何位置,使用 search() 来替代(也可参考 search() vs. match() )
匹配对象方法 | 描述 |
---|---|
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
Python 提供了两种不同的操作:基于 re.match() 检查字符串开头,或者 re.search() 检查字符串的任意位置(默认Perl中的行为)。
>>> re.match("c", "abcdef") # No match
>>> re.search("c", "abcdef") # Match
<_sre.SRE_Match object; span=(2, 3), match='c'>
-- 在 search() 中,可以用 '^' 作为开始来限制匹配到字符串的首位
>>> re.match("c", "abcdef") # No match
>>> re.search("^c", "abcdef") # No match
>>> re.search("^a", "abcdef") # Match
<_sre.SRE_Match object; span=(0, 1), match='a'>
-- 注意 MULTILINE 多行模式中函数 match() 只匹配字符串的开始,但使用 search() 和以 '^' 开始的正则表达式会匹配每行的开始
>>> re.match('X', 'A\nB\nX', re.MULTILINE) # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE) # Match
<_sre.SRE_Match object; span=(4, 5), match='X'>
3.3 re.fullmatch
语法:
re.fullmatch(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等 re.I (ignore case), re.M (multi-line), re.S (dot matches all), and re.X (verbose) |
如果整个 string 匹配到正则表达式样式,就返回一个相应的匹配对象 。 否则就返回一个 None ;注意这跟零长度匹配是不同的。
match从字符串开头开始匹配,匹配到目标的字符串即可成功返回(这个要跟search区分开,search不要求从头开始匹配);
fullmatch是完全匹配(从字符串开头到结尾)。
import re
qq = '1826755263'
re.match(r'[1-9]\d{4,11}', qq)
qq = '1826755263'
re.fullmatch(r'[1-9]\d{4,11}', qq)
# 用match实现fullmatch的功能
qq = '1826755263'
re.match(r'^[1-9]\d{4,11}$', qq)
3.4 re.split
语法:
re.split(pattern, string, maxsplit=0, flags=0)
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
maxsplit | 分隔次数,默认为0(即不限次数) |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等 re.I (ignore case), re.M (multi-line), re.S (dot matches all), and re.X (verbose) |
用 pattern 分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素
>>> import re
>>> re.split(r'\W+','Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split(r'(\W+)','Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>>
>>> re.split(r'\W+','Words, words, words.',1)
['Words', 'words, words.']
>>> re.split(r'\W+','Words, words, words.',2)
['Words', 'words', 'words.']
>>>
>>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
['0', '3', '9']
>>>
3.5 re.findall
语法:
re.findall(pattern, string, flags=0)
函数参数说明:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等 re.I (ignore case), re.M (multi-line), re.S (dot matches all), and re.X (verbose) |
对 string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。
>>> import re
>>> text = "He was carefully disguised but captured quickly by police."
>>> re.findall(r"\w+ly", text)
['carefully', 'quickly']
>>>
参考:
1.https://docs.python.org/zh-cn/3.6/library/re.html
2.https://blog.csdn.net/u011649536/article/details/50587915