正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex、regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。
正则表达式的“鼻祖”或许可一直追溯到科学家对人类神经系统工作原理的早期研究。美国新泽西州的Warren McCulloch和出生在美国底特律的Walter Pitts这两位神经生理方面的科学家,研究出了一种用数学方式来描述神经网络的新方法,他们创造性地将神经系统中的神经元描述成了小而简单的自动控制元,从而作出了一项伟大的工作革新。
在1951 年,一位名叫Stephen Kleene的数学科学家,他在Warren McCulloch和Walter Pitts早期工作的基础之上,发表了一篇题目是《神经网事件的表示法》的论文,利用称之为正则集合的数学符号来描述此模型,引入了正则表达式的概念。正则表达式被作为用来描述其称之为“正则集的代数”的一种表达式,因而采用了“正则表达式”这个术语。
正则表达式的特点:
- 灵活性、逻辑性和功能性非常强;
- 可以迅速地用极简单的方式达到字符串的复杂控制。
- 对于刚接触的人来说,比较晦涩难懂。
正则表达式的应用场景:
- 匹配 查看一个字符串是否符合正则表达式的语法,一般返回true或者false;
- 获取 正则表达式来提取字符串中符合要求的文本;
- 替换 查找字符串中符合正则表达式的文本,并用相应的字符串替换;
- 分割 使用正则表达式对字符串进行分割。
python使用正则表达式要导入re库。
#提取邮箱
pattern = re.compile(r"[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)")
strs = '我的私人邮箱是zhuwjwh@outlook.com,公司邮箱是123456@qq.org,麻烦登记一下?'
result = pattern.findall(strs)
print(result) #['zhuwjwh@outlook.com', '123456@qq.org’]
#提取身份证号
pattern = re.compile(r"[1-9]\d{5}(?:18|19|(?:[23]\d))\d{2}(?:(?:0[1-9])|(?:10|11|12))(?:(?:[0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]")
strs = '小明的身份证号码是342623198910235163,手机号是13987692110'
result = pattern.findall(strs)
print(result) #['342623198910235163’]
#提取电话号码
pattern = re.compile(r"\d{3}-\d{8}|\d{4}-\d{7}")
strs = '0511-1234567是小明家的电话,他的办公室电话是021-87654321'
result = pattern.findall(strs)
print(result) #['0511-1234567', '021-87654321']
正则表达式语法
正则表达式一般由普通字符、转义字符、特殊字符组成。
普通字符
字母、数字、汉字、下划线、以及没有特殊定义的标点符号,都是"普通字符"。表达式中的普通字符,在匹配一个字符串的时候,匹配与之相同的一个字符。
例如:表达式 “c”,在匹配字符串 “abcde” 时,匹配结果是:成功;匹配到的内容是:“c”;匹配到的位置是:开始于2,结束于3。(包含开始位置,不包含结束位置)例2:表达式 "bcd",在匹配字符串"abcde"时,匹配结果是:成功;匹配到的内容是:"bcd";匹配到的位置是:开始于1,结束于4。
转义字符
- 一些不便书写的字符,采用在前面加“\” 的方法。例如制表符、换行符等;
- 一些特殊字符,为了表示自己本来的含义,在前面加“\” 后,如{,}, [, ], /, \, +, *, ., $, ^, |, ? 等;
转义字符 | 说明 |
\n | 匹配换行符 |
\t | 匹配制表符 |
\\ | 匹配\符号 |
\^ | 匹配^符号 |
\$ | 匹配$符号 |
\. | 匹配.符号 |
\? | 匹配?符号 |
\* | 匹配*符号 |
\+ | 匹配+符号 |
\{、\} | 匹配大括号 |
\[、\] | 匹配中括号 |
\(、\) | 匹配小括号 |
\| | 匹配|符号 |
转义字符的匹配方法与“普通字符”类似,也是匹配与之相同的一个字符。
例如:表达式 "\$d",在匹配字符串 "abc$de" 时,匹配结果是:成功;匹配到的内容是:"$d";匹配到的位置是:开始于3,结束于5。
特殊字符
特殊字符在正则表达式中有特殊的语法含义
字符 | 描述 |
---|---|
. | 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于 [^0-9]。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\w | 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
\W | 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[...] | 用于表示一个字符集合。参见后面的补充说明 |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
* | 对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。 re* 会匹配 'r' ,'re' ,或者 'r' 后面跟随任意个 'e' 。 |
+ | 对它前面的正则式匹配1到任意次重复。 re+ 会匹配 'r' 后面跟随1个以上到任意个 'e' ,它不会匹配 'r' 。 |
? | 对它前面的正则式匹配0到1次重复。 re? 会匹配 'r' 或者 're' 。 |
{m} | 对其之前的正则式指定匹配 m 个重复;少于 m 的话就会导致匹配失败。比如, a{6} 将匹配6个 'a' , 但是不能是5个。 o{2} 不能匹配 "Bob" 中的 "o",但是能匹配 "food" 中的两个 o。 |
{m,n} | 对正则式进行 m 到 n 次匹配,在 m 和 n 之间取尽量多。 比如,a{3,5} 将匹配 3 到 5个 'a' 。 |
{m,} | 匹配至少m个前面表达式。例如, o{2,} 不能匹配"Bob"中的"o",但能匹配 "foooood"中的所有 o。"o{1,}" 等价于 "o+"。"o{0,}" 则等价于 "o*"。a{4,}b 将匹配 'aaaab' 或者1000个 'a' 尾随一个 'b' ,但不能匹配 'aaab' 。逗号不能省略,否则无法辨别修饰符应该忽略哪个边界。 |
{,n} | 匹配至多n个前面表达式 |
{m,n}? | 将导致结果 RE 匹配之前 RE 的 m 至 n 次重复,尝试匹配尽可能 少的 重复次数。 这是之前数量限定符的非贪婪版本。 例如,在 6 个字符的字符串 'aaaaaa' 上,a{3,5} 将匹配 5 个 'a' 字符,而 a{3,5}? 将只匹配 3 个字符。 |
{m,n}+ | 将导致结果 RE 匹配之前 RE 的 m 至 n 次重复,尝试匹配尽可能多的重复而 不会 建立任何反向追溯点。 这是上述数量限定符的占有型版本。 例如,在 6 个字符的字符串 |
a|b | 匹配a或b |
(...) | (组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用 \number 转义序列进行再次匹配,之后进行详细说明。要匹配字符 '(' 或者 ')' , 用 \( 或 \) , 或者把它们包含在字符集合里: [(] , [)] . |
(?...) | 这是个扩展标记法 (一个 '?' 跟随 '(' 并无含义)。 '?' 后面的第一个字符决定了这个构建采用什么样的语法。这种扩展通常并不创建新的组合; (?P<name>...) 是唯一的例外。针对这种扩展语法,参见补充说明。 |
\w | 匹配字母数字及下划线 |
\W | 匹配非字母数字及下划线 |
\s | 匹配任意空白字符,等价于 [ \t\n\r\f]。 |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9]. |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等. | 匹配一个换行符。匹配一个制表符。等 |
\1...\9 | 匹配第n个分组的内容。 |
\10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
补充说明:
[]
用于表示一个字符集合:
- 字符可以单独列出,比如 [amk] 匹配 'a', 'm', 或者 'k'。
- 可以表示字符范围,通过用 '-' 将两个字符连起来。比如 [a-z] 将匹配任何小写ASCII字符, [0-5][0-9] 将匹配从 00 到 59 的两位数字, [0-9A-Fa-f] 将匹配任何十六进制数位。 如果 - 进行了转义 (比如 [a\-z])或者它的位置在首位或者末尾(如 [-a] 或 [a-]),它就只表示普通字符 '-'。
- 特殊字符在集合中会失去其特殊意义。比如 [(+*)] 只会匹配这几个字面字符之一 '(', '+', '*', or ')'。
- 字符类如 \w 或者 \S (如下定义) 在集合内可以接受,它们可以匹配的字符由 ASCII 或者 LOCALE 模式决定。
- 不在集合范围内的字符可以通过 取反 来进行匹配。如果集合首字符是 '^' ,所有 不 在集合内的字符将会被匹配,比如 [^5] 将匹配所有字符,除了 '5', [^^] 将匹配所有字符,除了 '^'. ^ 如果不在集合首位,就没有特殊含义。
- 要在集合内匹配一个 ']' 字面值,可以在它前面加上反斜杠,或是将它放到集合的开头。 例如,[()[\]{}] 和 []()[{}] 都可以匹配右方括号,以及左方括号,花括号和圆括号。
- Unicode Technical Standard #18 里的嵌套集合和集合操作支持可能在未来添加。这将会改变语法,所以为了帮助这个改变,一个 FutureWarning 将会在有多义的情况里被 raise,包含以下几种情况,集合由 '[' 开始,或者包含下列字符序列 '--', '&&', '~~', 和 '||'。为了避免警告,需要将它们用反斜杠转义。
贪婪模式
在使用修饰匹配次数的特殊符号时,如“?”,“*”, “+”等,可以使同一个表达式能够匹配不同的次数,具体匹配的次数随被匹配的字符串而定。这种重复匹配不定次数的表达式在匹配过程中,总是尽可能多的匹配,这种匹配原则就叫作"贪婪" 模式 。
'*'
, '+'
和 '?'
数量限定符都是 贪婪的;它们会匹配尽可能多的文本。 有时这种行为并不被需要;如果 RE <.*>
针对 '<a> b <c>'
进行匹配,它将匹配整个字符串,而不只是 '<a>'
。 在数量限定符之后添加 ?
将使其以 非贪婪 或 最小 风格来执行匹配;也就是将匹配数量尽可能 少的 字符。 使用 RE <.*?>
将只匹配 '<a>'
。
*+
, ++
, ?+
类似于 '*'
, '+'
和 '?'
数量限定符,添加了 '+'
的形式也将匹配尽可能多的次数。 但是,不同于真正的贪婪型数量限定符,这些形式在之后的表达式匹配失败时不允许反向追溯。 这些形式被称为 占有型 数量限定符。 例如,a*a
将匹配 'aaaa'
因为 a*
将匹配所有的 4 个 'a'
,但是,当遇到最后一个 'a'
时,表达式将执行反向追溯以便最终 a*
最后变为匹配总计 3 个 'a'
,而第四个 'a'
将由最后一个 'a'
来匹配。 然而,当使用 a*+a
时如果要匹配 'aaaa'
,a*+
将匹配所有的 4 个 'a'
,但是在最后一个 'a'
无法找到更多字符来匹配时,表达式将无法被反向追溯并将因此匹配失败。 x*+
, x++
和 x?+
分别等价于 (?>x*)
, (?>x+)
和 (?>x?)
。
{m,n}、{m,n}?、{m,n}+
{m,n}对正则式进行 m 到 n 次匹配,在 m 和 n 之间取尽量多。 比如,a{3,5}
将匹配 3 到 5个 'a'
。{m,n}?将导致结果 RE 匹配之前 RE 的 m 至 n 次重复,尝试匹配尽可能 少的 重复次数。 这是之前数量限定符的非贪婪版本。 例如,在 6 个字符的字符串 'aaaaaa'
上,a{3,5}
将匹配 5 个 'a'
字符,而 a{3,5}?
将只匹配 3 个字符。{m,n}+将导致结果 RE 匹配之前 RE 的 m 至 n 次重复,尝试匹配尽可能多的重复而 不会 建立任何反向追溯点。 这是上述数量限定符的占有型版本。 例如,在 6 个字符的字符串 'aaaaaa'
上,a{3,5}+aa
将尝试匹配 5 个 'a'
字符,然后,要求再有 2 个 'a'
,这将需要比可用的更多的字符因而会失败,而 a{3,5}aa
的匹配将使 a{3,5}
先捕获 5 个,然后通过反向追溯再匹配 4 个 'a'
,然后用模式中最后的 aa
来匹配最后的 2 个 'a'
。 x{m,n}+
就等同于 (?>x{m,n})
。
>>> re.search(r'a{3,5}', 'baaac')
<re.Match object; span=(1, 4), match='aaa'>
>>> re.search(r'a{3,5}', 'baaaaaac')
<re.Match object; span=(1, 6), match='aaaaa'>
>>> re.search(r'a{3,5}?', 'baaaaaac')
<re.Match object; span=(1, 4), match='aaa'>
>>> re.search(r'a{3,5}+', 'baaaaaac')
<re.Match object; span=(1, 6), match='aaaaa'>
(?...)
扩展标记法,'?'
后面的第一个字符决定了这个构建采用什么样的语法。
(?aiLmsux)
( 'a', 'i', 'L', 'm', 's', 'u', 'x' 中的一个或多个) 这个组合匹配一个空字符串;这些字符对正则表达式设置以下标记 re.A (只匹配ASCII字符), re.I (忽略大小写), re.L (语言依赖), re.M (多行模式), re.S (点dot匹配全部字符), re.U (Unicode匹配), and re.X (冗长模式)。 (这些标记在 模块内容 中描述) 如果你想将这些标记包含在正则表达式中,这个方法就很有用,免去了在 re.compile() 中传递 flag 参数。标记应该在表达式字符串首位表示。
(?:…)
正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串 不能 在执行匹配后被获取或是之后在模式中被引用。
(?aiLmsux-imsx:…)
('a', 'i', 'L', 'm', 's', 'u', 'x' 中的0或者多个, 之后可选跟随 '-' 在后面跟随 'i' , 'm' , 's' , 'x' 中的一到多个 .) 这些字符为表达式的其中一部分 设置 或者 去除 相应标记 re.A (只匹配ASCII), re.I (忽略大小写), re.L (语言依赖), re.M (多行), re.S (点匹配所有字符), re.U (Unicode匹配), and re.X (冗长模式)。(标记描述在 模块内容 .)
'a', 'L' and 'u' 作为内联标记是相互排斥的, 所以它们不能结合在一起,或者跟随 '-' 。 当他们中的某个出现在内联组中,它就覆盖了括号组内的匹配模式。在Unicode样式中, (?a:...) 切换为 只匹配ASCII, (?u:...) 切换为Unicode匹配 (默认). 在byte样式中 (?L:...) 切换为语言依赖模式, (?a:...) 切换为 只匹配ASCII (默认)。这种方式只覆盖组合内匹配,括号外的匹配模式不受影响。
(?>...)
尝试匹配 ...
就像它是一个单独的正则表达式,如果匹配成功,则继续匹配在它之后的剩余表达式。 如果之后的表达式匹配失败,则栈只能回溯到 (?>...)
之前 的点,因为一旦退出,这个被称为 原子化分组 的表达式将会丢弃其自身所有的栈点位。 因此,(?>.*).
将永远不会匹配任何东西因为首先 .*
将匹配所有可能的字符,然后,由于没有任何剩余的字符可供匹配,最后的 .
将匹配失败。 由于原子化分组中没有保存任何栈点位,并且在它之前也没有任何栈点位,因此整个表达式将匹配失败。
(?P<name>…)
与常规圆括号类似,但组匹配的子字符串可以通过符号组名称访问。组名必须是有效的Python标识符,并且每个组名在正则表达式中只能定义一次。符号组也是一个有编号的组,就像该组没有命名一样。
命名组合可以在三种上下文中引用。如果样式是 (?P<quote>['"]).*?(?P=quote)
(也就是说,匹配单引号或者双引号括起来的字符串):
引用组合 "quote" 的上下文 |
引用方法 |
---|---|
在正则式自身内 |
|
处理匹配对象 m |
|
传递到 |
|
(?P=name)
反向引用一个命名组合;它匹配前面那个叫 name 的命名组中匹配到的串同样的字串。
(?#…)
注释;里面的内容会被忽略。
前瞻(?=…)
exp1(?=exp2) exp1
后面的内容要匹配exp2
当 …
匹配时,匹配成功,但不消耗字符串中的任何字符。这个叫做 前视断言 (lookahead assertion)。比如, Isaac (?=Asimov)
将会匹配 'Isaac '
,仅当其后紧跟 'Asimov'
。
负前瞻(?!…)
exp1(?!exp2) exp1
后面的内容不能匹配exp2
当 …
不匹配时,匹配成功。这个叫 否定型前视断言 (negative lookahead assertion)。例如, Isaac (?!Asimov)
将会匹配 'Isaac '
,仅当它后面 不是 'Asimov'
。
后顾(?<=…)
(?<=exp2)exp1 exp1
前面的内容要匹配exp2
如果 ...
的匹配内容出现在当前位置的左侧,则匹配。这叫做 肯定型后视断言 (positive lookbehind assertion)。 (?<=abc)def
将会在 'abcdef'
中找到一个匹配,因为后视会回退3个字符并检查内部表达式是否匹配。内部表达式(匹配的内容)必须是固定长度的,意思就是 abc
或 a|b
是允许的,但是 a*
和 a{3,4}
不可以。注意,以肯定型后视断言开头的正则表达式,匹配项一般不会位于搜索字符串的开头。
>>> m = re.search('(?<=abc)def', 'abcdef')
>>> m.group(0)
'def'
>>> m = re.search(r'(?<=-)\w+', 'spam-egg')
>>> m.group(0)
'egg'
负后顾(?<!…)
(?<!exp2)exp1 exp1
前面的内容不能匹配exp2
如果 ...
的匹配内容没有出现在当前位置的左侧,则匹配。这个叫做 否定型后视断言 (negative lookbehind assertion)。类似于肯定型后视断言,内部表达式(匹配的内容)必须是固定长度的。以否定型后视断言开头的正则表达式,匹配项可能位于搜索字符串的开头。
>>> re.search(r'(?<!-)\w+', 'spam-egg')
<re.Match object; span=(0, 4), match='spam'>
>>> re.search(r'(?<=-)\w+', 'spam-egg')
<re.Match object; span=(5, 8), match='egg'>
条件匹配(?(id/name)yes-pattern|no-pattern)
对应id的子表达式如果匹配到内容,则这里匹配yes_exp,否则匹配no_exp
如果给定的 id 或 name 存在,将会尝试匹配 yes-pattern
,否则就尝试匹配 no-pattern
,no-pattern
可选,也可以被忽略。比如, (<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$)
是一个email样式匹配,将匹配 '<user@host.com>'
或 'user@host.com'
,但不会匹配 '<user@host.com'
,也不会匹配 'user@host.com>'
。
由 '\'
和一个字符组成的特殊序列在以下列出。 如果普通字符不是ASCII数位或者ASCII字母,那么正则样式将匹配第二个字符。比如,\$
匹配字符 '$'
.
主要函数
- re库是Python的标准库,不需要额外安装,主要用于字符串匹配
- 调用方式:import re
- re 库采用raw string类型表示正则表达式,rawstring是不包含对转义符再次转义的字符串。例如:r'[1‐9]\d{5}’
- re库也可以采用string类型表示正则表达式,但更繁琐,例如“'[1‐9]\\d{5}'”
- 当正则表达式包含转义符时,建议使用raw string
主要功能函数有:
函数 | 说明 |
re.seach() | 扫描整个字符串并返回第一个成功的匹配 |
re.match() | 尝试从字符串的起始位置匹配一个模式 |
re.fullmatch() | 完全匹配,即从字符串开始到结束都能匹配正则表达式 |
re.findall() | 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的,则返回空列表。 |
re.finditer() | 和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。 |
re.split() | 按照能够匹配的子串将字符串分割后返回列表 |
re.sub() re.subn() |
替换掉所有匹配正则表达式的子串 |
re.compile() | 编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。 |
re.seach()
re.search(pattern, string, flags=0)
参数说明:
- pattern:匹配的正则表达式
- string:要匹配的字符串。
- flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
扫描整个字符串并返回第一个成功的匹配。
>>> import re
>>> re.search('www', 'www.csdn.net')
<re.Match object; span=(0, 3), match='www'>
>>> re.search('www', 'www.csdn.net').span()
(0, 3)
>>> re.search('csdn', 'www.csdn.net').span()
(4, 8)
从上面的例子可以看到,search()返回的是re.Match对象。
标志位
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
标志位 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
re.match()
re.match(pattern, string, flags=0)
参数说明:
- pattern:匹配的正则表达式
- string:要匹配的字符串。
- flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
>>> re.match('www', 'www.csdn.net').span()
(0, 3)
>>> re.match('csdn', 'www.csdn.net').span()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'span'
re.Match
由成功的 match
和 search
所返回的匹配对象。
主要方法和属性:
方法和属性名 | 说明 |
Match.span([group]) | 对于一个匹配 m , 返回一个二元组 (m.start(group), m.end(group)) 。 注意如果 group 没有在这个匹配中,就返回 (-1, -1) 。group 默认为0,就是整个匹配。 |
Match.groups(default=None) | 返回一个元组,包含所有匹配的子组,在样式中出现的从1到任意多的组合。 default 参数用于不参与匹配的情况,默认为 None 。 |
Match.start([group]) Match.end([group]) |
返回 group 匹配到的字串的开始和结束标号。group 默认为0(意思是整个匹配的子串)。如果 group 存在,但未产生匹配,就返回 -1 。对于一个匹配对象 m, 和一个未参与匹配的组 g ,组 g (等价于 m.group(g) )产生的匹配是m.string[m.start(g):m.end(g)] |
Match.expand(template) | 对 template 进行反斜杠转义替换并且返回,就像 sub() 方法中一样。转义如同 \n 被转换成合适的字符,数字引用(\1, \2)和命名组合(\g<1>, \g<name>) 替换为相应组合的内容。 |
Match.group([group1, ...]) | 返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串,如果有多个参数,结果就是一个元组(每个参数对应一个项),如果没有参数,组1默认到0(整个匹配都被返回)。 如果一个组N 参数值为 0,相应的返回值就是整个匹配字符串;如果它是一个范围 [1..99],结果就是相应的括号组字符串。如果一个组号是负数,或者大于样式中定义的组数,就引发一个 IndexError 异常。如果一个组包含在样式的一部分,并被匹配多次,就返回最后一个匹配。 |
Match.__getitem__(g) | 等价于 m.group(g)
|
Match.groupdict(default=None) | 返回一个字典,包含了所有的 命名 子组。key就是组名。 default 参数用于不参与匹配的组合;默认为 None 。 |
Match.pos | pos 的值,会传递给 search() 或 match() 的方法 a 正则对象 。这个是正则引擎开始在字符串搜索一个匹配的索引位置。 |
Match.endpos | endpos 的值,会传递给 search() 或 match() 的方法 a 正则对象 。这个是正则引擎停止在字符串搜索一个匹配的索引位置。 |
Match.lastindex | 捕获组的最后一个匹配的整数索引值,或者 None 如果没有匹配产生的话。比如,对于字符串 'ab' ,表达式 (a)b , ((a)(b)) , 和 ((ab)) 将得到 lastindex == 1 , 而 (a)(b) 会得到 lastindex == 2 。 |
Match.lastgroup | 最后一个匹配的命名组名字,或者 None 如果没有产生匹配的话。 |
Match.re | 返回产生这个实例的 正则对象 , 这个实例是由 正则对象的 match() 或 search() 方法产生的。 |
Match.string | 传递到 match() 或 search() 的字符串。 |
注意:group在Match中是一个非常重要的概念,它是通过小括号匹配出来的一段,而不是多个匹配的串。
>>> m=re.match(r'(\d{4})[/-](\d{2})[/-](\d{2})', '2023-09-17 && 2022-08-11')
>>> m
<re.Match object; span=(0, 10), match='2023-09-17'>
>>> m.groups()
('2023', '09', '17')
上面的例子可以看到,string中有两个可以匹配上的子串,但match只匹配了第一个子串,而所谓的组就是这个匹配的串中,如果在正则表达式中有小括号,则表示的是小括号的匹配子串。如果正则表达式中没有小括号来分组,就不会有groups的内容。
>>> m=re.match(r'\d{4}[/-]\d{2}[/-]\d{2}', '2023-09-17 && 2022-08-11')
>>> m
<re.Match object; span=(0, 10), match='2023-09-17'>
>>> m.groups()
()
groups表示的是匹配的字符串元组,group是指定取其中的一个,也可以通过[]按下标去取,如果取第0个,会把所有的都取出来。
>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0)
'Isaac Newton'
>>> m.group(1)
'Isaac'
>>> m[0]
'Isaac Newton'
>>> m[1]
'Isaac'
>>> m[2]
'Newton'
>>> m[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: no such group
>>> m.groups()
('Isaac', 'Newton')
>>> m.lastindex
2
>>> m.lastgroup
>>> m.re
re.compile('(\\w+) (\\w+)')
>>> m.string
'Isaac Newton, physicist’
>>> m.span()
(0, 12)
>>> m.span(1)
(0, 5)
>>> m.start()
0
>>> m.end()
12
>>> m.end(1)
5
>>> m.groupdict()
{}
>>> m.pos
0
>>> m.endpos
23
re.fullmatch()
re.fullmatch(pattern, string, flags=0)
参数:
- pattern:匹配的正则表达式
- string:要匹配的字符串。
- flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
如果整个 string 与此正则表达式匹配,则返回相应的 Match。 如果字符串与模式不匹配则返回 None;请注意这与零长度匹配是不同的。
>>> re.fullmatch('o[gh]', 'dog')
>>> m = re.fullmatch('o[gh]', 'dog')
>>> m
>>> m = re.fullmatch('o[gh]', 'ogg')
>>> m
>>> m = re.fullmatch('o[gh]', 'oh')
>>> m
<re.Match object; span=(0, 2), match='oh'>
re.findall()
re.findall(pattern, string, flags=0)
参数:
- pattern:匹配的正则表达式
- string:要匹配的字符串。
- flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
在字符串中找到正则表达式所匹配的所有子串(不是Match对象),并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次,而 findall是匹配所有。
>>> m = re.findall(r'\d+', 'python3 c++2 Java18')
>>> m
['3', '2', '18']
>>> type(m)
<class 'list'>
>>> re.findall("(ab)*","aabz1144c")
['', 'ab', '', '', '', '', '', '', '']
>>> re.findall("(ab)+","aabz1144c")
['ab']
re.finditer()
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
re.finditer(pattern, string, flags=0)
参数说明:
- pattern:匹配的正则表达式
- string:要匹配的字符串。
- flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
import re
it = re.finditer(r'\d+', 'abc123efg5994&&&*987---')
print(type(it))
for m in it:
print(m)
‘’’
<class 'callable_iterator'>
<re.Match object; span=(3, 6), match='123'>
<re.Match object; span=(9, 13), match='5994'>
<re.Match object; span=(17, 20), match='987’>
’‘’
re.split()
按照能够匹配的子串将字符串分割后返回列表
re.split(pattern, string[, maxsplit=0, flags=0])
参数说明:
- pattern:匹配的正则表达式
- string:要匹配的字符串。
- maxsplit:分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。
- flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
>>> re.split(r'\W+', 'python.org,Python-c,PYTHON+JAVA.python*',0,re.I)
['python', 'org', 'Python', 'c', 'PYTHON', 'JAVA', 'python', '']
>>> re.split(r'\d', 'one1two2three3four4')
['one', 'two', 'three', 'four', '']
>>> re.split(r'\d', 'one1two20three3four4')
['one', 'two', '', 'three', 'four', '']
>>> re.split(r'\d+', 'one1two20three3four4')
['one', 'two', 'three', 'four', '']
>>> re.split(r'\b', 'one two cc three four')
['', 'one', ' ', 'two', ' ', 'cc', ' ', 'three', ' ', 'four', '']
>>> re.split(r' ', 'one two cc three four')
['one', 'two', 'cc', 'three', 'four']
re.sub()
re.sub(pattern, repl, string, count=0, flags=0)
参数说明:
- pattern : 正则表达式
- repl : 替换的字符串,也可为一个函数。
- string : 要被查找替换的原始字符串。
- count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
import re
phone = "081-956-559 # 这是一个国外电话号码"
# 删除字符串中的 Python注释
num = re.sub(r'#.*$', '', phone)
print("电话号码是: ", num) #电话号码是: 081-956-559
# 删除非数字(-)的字符串
num = re.sub(r'\D', '', phone)
print("电话号码是 : ", num) #电话号码是 : 081956559
如果 repl 是一个函数,则它会针对每次 pattern 的非重叠出现的情况被调用。 该函数接受单个 Match 参数,并返回替换字符串。 例如:
import re
# 将匹配的数字乘以 2
def double(matched):
value = int(matched.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))
‘’'
A46G8HFD1134
‘''
re.subn()
行为与 sub() 相同,但是返回一个元组 (字符串, 替换次数).
re.subn(pattern, repl, string, count=0, flags=0)
re.compile()
用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。 re.compile(pattern[, flags])
参数说明:
- pattern : 一个字符串形式的正则表达式
- flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
>>>import re
>>> pattern = re.compile(r'\d+') # 用于匹配至少一个数字
>>> m = pattern.match('one12twothree34four') # 查找头部,没有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
>>> print m # 返回一个 Match 对象
<_sre.SRE_Match object at 0x10a42aac0>
>>> m.group(0) # 可省略 0
'12'
>>> m.start(0) # 可省略 0
3
>>> m.end(0) # 可省略 0
5
>>> m.span(0) # 可省略 0
(3, 5)
class re.Pattern
由 re.compile() 返回的已编译正则表达式对象。
主要的属性和方法有:
Pattern.search(string[, pos[, endpos]])
扫描整个 string 查找该正则表达式产生匹配的第一个位置,并返回相应的 Match。 如果字符串中没有与模式匹配的位置则返回 None;请注意这不同于在字符串的某个位置上找到零长度匹配。
可选的第二个参数 pos 给出了字符串中开始搜索的位置索引;默认为 0,它不完全等价于字符串切片; '^' 样式字符匹配字符串真正的开头,和换行符后面的第一个字符,但不会匹配索引规定开始的位置。
可选参数 endpos 限定了字符串搜索的结束;它假定字符串长度到 endpos , 所以只有从 pos 到 endpos - 1 的字符会被匹配。如果 endpos 小于 pos,就不会有匹配产生;另外,如果 rx 是一个编译后的正则对象, rx.search(string, 0, 50) 等价于 rx.search(string[:50], 0)。
>>>pattern = re.compile("d")
>>>pattern.search("dog") # Match at index 0
<re.Match object; span=(0, 1), match='d'>
>>>pattern.search("dog", 1) # No match; search doesn't include the "d"
Pattern.match(string[, pos[, endpos]])
如果字符串 开头 的零个或多个字符与此正则表达式匹配,则返回相应的 Match。 如果字符串与模式不匹配则返回 None;请注意这与零长度匹配是不同的。
可选参数 pos 和 endpos 与 search() 含义相同。
>>>pattern = re.compile("o")
>>>pattern.match("dog") # No match as "o" is not at the start of "dog".
>>>pattern.match("dog", 1) # Match as "o" is the 2nd character of "dog".
<re.Match object; span=(1, 2), match='o'>
Pattern.fullmatch(string[, pos[, endpos]])
如果整个 string 与此正则表达式匹配,则返回相应的 Match。 如果字符串与模式不匹配则返回 None;请注意这与零长度匹配是不同的。
可选参数 pos 和 endpos 与 search() 含义相同。
>>>pattern = re.compile("o[gh]")
>>>pattern.fullmatch("dog") # No match as "o" is not at the start of "dog".
>>>pattern.fullmatch("ogre") # No match as not the full string matches.
>>>pattern.fullmatch("doggie", 1, 3) # Matches within given limits.
<re.Match object; span=(1, 3), match='og'>
Pattern.split(string, maxsplit=0)
等价于 split() 函数,使用了编译后的样式。
Pattern.findall(string[, pos[, endpos]])
类似函数 findall() , 使用了编译后样式,但也可以接收可选参数 pos 和 endpos ,限制搜索范围,就像 search()。
Pattern.finditer(string[, pos[, endpos]])
类似函数 finditer() , 使用了编译后样式,但也可以接收可选参数 pos 和 endpos ,限制搜索范围,就像 search()。
Pattern.sub(repl, string, count=0)
等价于 sub() 函数,使用了编译后的样式。
Pattern.subn(repl, string, count=0)
等价于 subn() 函数,使用了编译后的样式。
Pattern.flags
正则匹配标记。这是可以传递给 compile() 的参数,任何 (?…) 内联标记,隐性标记比如 UNICODE 的结合。
Pattern.groups
捕获到的模式串中组的数量。
Pattern.groupindex
映射由 (?P<id>) 定义的命名符号组合和数字组合的字典。如果没有符号组,那字典就是空的。
Pattern.pattern
编译对象的原始样式字符串。
re.escape(pattern)
转义 pattern 中的特殊字符。如果你想对任意可能包含正则表达式元字符的文本字符串进行匹配,它就是有用的。
>>>print(re.escape('https://www.python.org'))
https://www\.python\.org
>>>legal_chars = string.ascii_lowercase + string.digits + "!#$%&'*+-.^_`|~:"
>>>print('[%s]+' % re.escape(legal_chars))
[abcdefghijklmnopqrstuvwxyz0123456789!\#\$%\&'\*\+\-\.\^_`\|\~:]+
>>>operators = ['+', '-', '*', '/', '**']
>>>print('|'.join(map(re.escape, sorted(operators, reverse=True))))
/|\-|\+|\*\*|\*
re.purge()
清除正则表达式的缓存。
常用正则表达式
邮箱
包含大小写字母,下划线,阿拉伯数字,点号,中划线
表达式:
[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)
>>> re.match(r'[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)', 'ssxw@qq.com')
<re.Match object; span=(0, 11), match='ssxw@qq.com'>
>>> re.search(r'[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)', 'my email is ssxw@qq.com.')
<re.Match object; span=(12, 23), match='ssxw@qq.com'>
身份证号码
xxxxxx yyyy MM dd 375 0 十八位
- 地区: [1-9]\d{5}
- 年的前两位: (18|19|([23]\d)) 1800-2399
- 年的后两位: \d{2}
- 月份: ((0[1-9])|(10|11|12))
- 天数: (([0-2][1-9])|10|20|30|31) 闰年不能禁止29+
- 三位顺序码: \d{3}
- 两位顺序码: \d{2}
- 校验码: [0-9Xx]
表达式:
[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]
>>> re.match(r'[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]', '450104197710101516')
<re.Match object; span=(0, 18), match='450104197710101516'>
国内手机号码
手机号都为11位,且以1开头,第二位一般为3、5、6、7、8、9 ,剩下八位任意数字
例如:13987692110、15610098778
表达式:
1(3|4|5|6|7|8|9)\d{9}
>>> re.search(r'1(3|4|5|6|7|8|9)\d{9}', '我的手机号为:17910880306,希望常联系')
<re.Match object; span=(7, 18), match='17910880306'>
国内固定电话
区号3\~4位,号码7\~8位
例如:0571-1234567、010-87654321
表达式:
\d{3}-\d{8}|\d{4}-\d{7}
>>> re.search(r'\d{3}-\d{8}|\d{4}-\d{7}', 'Our phone number is 010-68820403. Welcome to inquire')
<re.Match object; span=(20, 32), match='010-68820403'>
域名
包含http:\\或https:\\
表达式:
(?:(?:http:\/\/)|(?:https:\/\/))?(?:[\w](?:[\w\-]{0,61}[\w])?\.)+[a-zA-Z]{2,6}(?:\/)?
>>> re.search(r'(?:(?:http:\/\/)|(?:https:\/\/))?(?:[\w](?:[\w\-]{0,61}[\w])?\.)+[a-zA-Z]{2,6}(?:\/)?', 'The official website address of Python is http://www.python.org')
<re.Match object; span=(42, 63), match='http://www.python.org'>
IP地址
IP地址的长度为32位(共有2^32个IP地址),分为4段,每段8位,用十进制数字表示
每段数字范围为0~255,段与段之间用句点隔开
表达式:
((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))
>>> re.search(r'((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))', 'IP192.168.1.4')
<re.Match object; span=(2, 13), match='192.168.1.4'>
日期
常见日期格式:yyyyMMdd、yyyy-MM-dd、yyyy/MM/dd、yyyy.MM.dd
表达式:
\d{4}(?:-|\/|.)\d{1,2}(?:-|\/|.)\d{1,2}
>>> re.search(r'\d{4}(?:-|\/|.)\d{1,2}(?:-|\/|.)\d{1,2}', 'Yesterday2023-9-17, was a sad day')
<re.Match object; span=(9, 18), match='2023-9-17'>
国内邮政编码
我国的邮政编码采用四级六位数编码结构
前两位数字表示省(直辖市、自治区)
第三位数字表示邮区;第四位数字表示县(市)
最后两位数字表示投递局(所)
表达式:
[1-9]\d{5}(?!\d)
>>> re.search(r'[1-9]\d{5}(?!\d)', 'BEIJING100073')
<re.Match object; span=(7, 13), match='100073'>
中文字符
表达式:文章来源:https://uudwc.com/A/8d4PY
[\u4e00-\u9fa5]
文章来源地址https://uudwc.com/A/8d4PY
>>> re.search(r'[\u4e00-\u9fa5]+', 'name:李寻欢')
<re.Match object; span=(5, 8), match='李寻欢'>
>>>
数字
- 验证数字:
^[0-9]*$
- 验证n位的数字:
^\d{n}$
- 验证至少n位数字:
^\d{n,}$
- 验证m-n位的数字:
^\d{m,n}$
- 验证零和非零开头的数字:
^(0|[1-9][0-9]*)$
- 验证有两位小数的正实数:
^[0-9]+(.[0-9]{2})?$
- 验证有1-3位小数的正实数:
^[0-9]+(.[0-9]{1,3})?$
- 验证非零的正整数:
^\+?[1-9][0-9]*$
- 验证非零的负整数:
^\-[1-9][0-9]*$
- 验证非负整数(正整数 + 0)
^\d+$
- 验证非正整数(负整数 + 0)
^((-\d+)|(0+))$
- 整数:
^-?\d+$
- 非负浮点数(正浮点数 + 0):
^\d+(\.\d+)?$
- 正浮点数
^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
- 非正浮点数(负浮点数 + 0)
^((-\d+(\.\d+)?)|(0+(\.0+)?))$
- 负浮点数
^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
- 浮点数
^(-?\d+)(\.\d+)?$
字符串
- 英文和数字:
^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
- 长度为3-20的所有字符:
^.{3,20}$
- 由26个英文字母组成的字符串:
^[A-Za-z]+$
- 由26个大写英文字母组成的字符串:
^[A-Z]+$
- 由26个小写英文字母组成的字符串:
^[a-z]+$
- 由数字和26个英文字母组成的字符串:
^[A-Za-z0-9]+$
- 由数字、26个英文字母或者下划线组成的字符串:
^\w+$ 或 ^\w{3,20}$
- 中文、英文、数字包括下划线:
^[\u4E00-\u9FA5A-Za-z0-9_]+$
- 中文、英文、数字但不包括下划线等符号:
^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
- 可以输入含有^%&',;=?$\”等字符:
[^%&',;=?$\x22]+
- 禁止输入含有\~的字符:
[^~\x22]+