Python中的正则表达式(三)
2020-05-12
作者:老齐
与本文相关的图书推荐:《跟老齐学Python:轻松入门》
《Python正则表达式》这个系列,已经完成了两篇,本文是第三篇,请继续阅读。
如果错过了前两篇,请关注微信公众号:老齐教室。
量词元字符
量词元字符,在正则表达式中表示匹配若干个字符,可能是0个、1个或者多个。
*
*
在正则表达式中表示匹配0个或者多个字符,例如a*
,就表示匹配0个或者更多个字符a
,例如可以匹配空字符串、a
、aaa
等等。
1 | >>> re.search('foo-*bar', 'foobar') # 匹配0个横线 |
上面示例中的正则表达式foo-*bar
,意思是在foo
三个字符之后,匹配0个或者更多个-
,然后是三个字符bar
。foobar
中foo
之后没有-
,即0个,并且最后三个字符是bar
,符合正则表达式的规则;foo--bar
则是匹配了两个-
字符。
前面已经介绍过.
,表示任何字符(除了换行符),如果和*
组合,即.*
表示0个或者任意多个任何字符(除了换行符),换句话说,匹配字符串中任何字符,直到改行结束(遇到换行符)。
1 | >>> re.search('foo.*bar', '# foo $qux@grault % bar #') |
对于字符串'# foo $qux@grault % bar #'
,按照正则表达式foo.*bar
进行匹配,从第索引为2的字符开始,符合正则表达式的规则,直到索引为23的字符为止,即匹配了f
(含)和r
(含)之间的所有字符。特别注意观察返回结果中span
和match
的值。
+
+
与上面的*
类似,但是,它匹配的是1个或多个字符,即至少要有一个。
1 | >>> print(re.search('foo-+bar', 'foobar')) # 0个横线,不匹配 |
通过上面演示的示例,比较*
和+
的差异。
?
前面已经有匹配“0个或多个”和“1个或多个”的元字符了,现在应该有匹配0个或1个的了,那就是?
。
1 | >>> re.search('foo-?bar', 'foobar') # 0个,匹配 |
下面的示例,将前面三个云字符进行比较,进一步理解它们的含义。
1 | >>> re.match('foo[1-9]*bar', 'foobar') |
foo[1-9]*bar
,匹配foo
和bar
之间有1~9的数字0个或多个。foo[1-9]+bar
,匹配foo
和bar
之间有1~9的数字1个或多个。foo[1-9]?bar
,匹配foo
和bar
之间有1~9的数字0个或1个。
以上三种量词元字符,还经常组合使用,例如:*?
、+?
、??
等。
1 | >>> re.search('<.*>', '%<foo> <bar> <baz>%') |
上面示例中的<.*>
表示要匹配<
字符之后的任何字符(除了换行字符),然后是>
。按照这个规则,匹配了'%<foo> <bar> <baz>%'
中的<foo> <bar> <baz>
,但是,如果只想匹配<foo>
怎么办?
1 | >>> re.search('<.*?>', '%<foo> <bar> <baz>%') |
上面使用了*?
,这种表示可以称为惰性匹配,也将此组合称为惰性量词,对应着,前面提到的*
等则称为贪婪量词,对应的匹配是贪婪匹配。下面以表格形式列出它们之间的比较(顺便也增加了另外一种“支配量词”,一并列出进行比较)。
贪婪量词 | 惰性量词 | 支配量词 | 描述 |
---|---|---|---|
* | *? | *+ | 可以不出现,也可以出现任意次 |
? | ?? | ?+ | 可以出现0次或1次 |
+ | +? | ++ | 至少出现1次或以上 |
{n} | {n}? | {n}+ | 有且只能出现n次 |
{n,m} | {n,m}? | {n,m}+ | 至少出现n次,至多出现m次 |
{n,} | {n,}? | {n,}+ | 至少出现n次或以上 |
- 贪婪匹配:如果符合要求就一直往后匹配,一直到无法匹配为止。
- 惰性匹配:一旦匹配到合适的就结束,不在继续匹配下去了。
- 支配匹配:只尝试匹配整个字符串。如果整个字符串不匹配,则不做进一步。
结合线面示例,理解上述匹配模式。
1 | >>> re.search('<.+>', '%<foo> <bar> <baz>%') |
{m}
{m}
表示匹配m
个字符。
1 | >>> print(re.search('x-{3}x', 'x--x')) # 2个横线,不匹配 |
x-{3}x
表示要匹配x
字符后面有3个-
,再接x
的字符串。
{m,n}
{m,n}
表示匹配大于等于m,小于等于n个字符,例如-{2,4}
可以匹配2个、3个、4个-
。
1 | >>> for i in range(1, 6): |
有时候会省略m或者n,其含义分别为:
{, n}
,等效于{0, n}
{m, }
,匹配大于等于m个字符{, }
,等效{0, }
或者*
注意,如果只是{}
,则表示花括号那个字符了。
1 | >>> re.search('x{}y', 'x{}y') |
{m,n}?
如前面表格所示,这是一种惰性量词,它表示匹配m到n个字符,只要匹配到了,就结束。例如:
1 | >>> re.search('a{3,5}', 'aaaaaaaa') |
a{3,5}
是贪婪匹配,要匹配到最大长度,即5个字符a;而a{3,5}?
是惰性匹配,只匹配3个字符a即可。
(未完,待续)
参考资料:https://realpython.com/regex-python/
搜索技术问答的公众号:老齐教室
在公众号中回复:老齐,可查看所有文章、书籍、课程。
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
关注微信公众号,读文章、听课程,提升技能