Python常用模块6-Python的re模块简介

一.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. ^[1-9] 开头是1-9的一个数字
  2. \d{13,16} 中间是最少13个数字,最多16个数字
  3. [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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容