Python中的正则表达式(二)
2020-05-09
作者:老齐
与本文相关的图书推荐:《跟老齐学Python:轻松入门》
在上一篇(《Python正则表达式(一)》)中,已经介绍了正则表达式的基本含义,并且对re
模块中的元字符[ ]
进行了说明,本文接续上文,介绍有关元字符。
re
模块的元字符
点(.
)
点.
(注意必须是英文状态下的)是一个通配符,即表示了任何符号(换行符除外)。
1 | >>> re.search('foo.bar', 'fooxbar') |
在上面示例中,正则表达式foo.bar
表示的匹配规则是:先是三个字符foo
,然后用通配符.
说明第四个字符可以是除了换行符之外的任何字符,第五个及其后的字符是bar
。显然,fooxbar
符合这个规则,而foobar
和foo\nbar
不符合,前者foo
之后是b
,但b
之后是ar
而不是bar
;后者中间是一个换行符\n
。
\w
和\W
\w
匹配全部由字母和数字组成的字符串,即大写、小写字母以及0到9的数字,注意,也包括下划线。通常,也可以用[a-zA-Z0-9]
来替代它。
1 | >>> re.search('\w', '#(.a$@&') |
显然,字符串'#(.a$@&'
中只有一个字母,上面演示中也都显示,匹配了字母a
。
如果是\W
(大写),则意味着与\w
相反,不包括字母、数字和下划线。
1 | >>> re.search('\W', 'a_1*3Qb') |
字符串'a_1*3Qb'
中的*
不属于字母、数字、下划线集合,在上述示例中匹配到了。注意,[^a-zA-Z0-9_]
中以^
开头,表示对后面字符集合的补集(取反)。
\d
和\D
\d
匹配由数字组成的字符,与[0-9]
相当。\D
同样是\d
取反,即[^0-9]
。
1 | >>> re.search('\d', 'abc4def') |
\s
和\S
\s
匹配任何空白字符,包括空格、制表符、换行符等等。等价于 [\f\n\r\t\v]
。
1 | >>> re.search('\s', 'foo\nbar baz') |
与前面一样,\S
也是对\s
取反,不匹配任何空白字符。
1 | >>> re.search('\S', ' \n foo \n ') |
上面几个元字符,也可以写到一个集合中。
1 | >>> re.search('[\d\w\s]', '---3---') |
[\d\w\s]
的含义就是匹配任何数字、字母和空白字符,-
则不在匹配之列。
转义符
跟Python中的字符串中规定一样,在正则表达式中,也用\
表示对后面的字符转移。
1 | >>> re.search('.', 'foo.bar') |
第一个示例中的.
,表示的是通配符,即任何字符。因此匹配了后面字符串中的第一个f
。第二个示例中的\.
,因为使用了转移符,它表示要匹配一个英文的句点,不再是通配符了,所以最终匹配了后面字符串中的句点符号。
使用\
,需要特别小心。
1 | >>> s = r'foo\bar' |
这里创立了原始字符串s
,注意,如果单单看print(s)
的结果,容易产生误解。因为这里使用了原始字符串r'foo\bar
,其中的\
就表示了原本的反斜杠符号,而不是转义符。当执行s
时,会看到,Python解析器会将其解析为'foo\\bar'
,也就是这种方式的字符串和前面定义的原始字符串是一样的,或者说前面定义原始字符串,在Python使用它的时候,会被解析为'foo\\bar'
,这就是我们要注意的地方。
下面要匹配s
里面的\
,按照通常方法,这样来试试:
1 | >>> re.search('\\', s) |
出问题了,原因就在于Python解析器实际使用的是'foo\\bar'
,那么,这里就有了两个反斜杠,第一个反斜杠表示的是“转移符”,并把这个符号传给了re.search()
,正则表达式收到了单个反斜杠,但这不是有意义字符,因此会出现混乱,导致了错误。
下面演示两种解决方式:
1 | >>> re.search('\\\\', s) |
或者:
1 | >>> re.search(r'\\', s) |
定位字符
定位字符是零宽度匹配,表示定位的符号不匹配字符串中的任何实际字符,并且不会使用任何搜索字符串。定位字符指示搜索字符串中必须发生匹配的特定位置。
^
或\A
^
或\A
表示匹配输入字符串的开始位置。但是,当它们在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合,即补集或相反。如果要匹配^
字符本身,必须要用\^
。
1 | >>> re.search('^foo', 'foobar') |
正则表达式^foo
表示要匹配以foo
开头的字符串,'foobar'
符合规则,'barfoo'
不符合规则。
\A
的作用与^
一样。
1 | >>> re.search('\Afoo', 'foobar') |
$
或\Z
与前述^
相对应,$
表示在字符串的结尾部分搜索相应匹配。
1 | >>> re.search('bar$', 'foobar') |
上面的示例中,bar$
表示搜索字符串结尾是bar
,foobar
符合此正则表达式的规则,barfoo
则不符合。在这里,\Z
与$
的效果一样。
但是,如果在下面的示例中,就只能使用$
。
1 | >>> re.search('bar$', 'foobar\n') |
\b
\b
匹配一个单词(也包括中文字符)的边界,即单词的分界。
例如这样一句话:Laoqi Classroom
,其中每个字符都有一个位置,包括空白(空格)也如此。如果某个字符后面的字符不是字母、数字和下划线,即不全是\w
所匹配的字符,那么\b
就会匹配后面的字符的后面(但不是下一个字符)。例如这句话中i
后面是空格,不在\w
范围内,那么\b
就会匹配空格后面、C
前面的位置。
例如:
1 | >>> re.search(r'\bbar', 'foo bar') |
字符串foo bar
中有空格,正则表达式r'\bbar'
就匹配这个字符后面的位置,并且此位置之后是bar
。同理foo.bar
亦然。
但是:
1 | >>> print(re.search(r'\bbar', 'foobar')) |
则不然。因为foobar
本身没有\b
要匹配的位置。
1 | >>> re.search(r'foo\b', 'foo bar') |
按照前述解释,上面示例不难理解。读者可以自己尝试梳理一番。
1 | >>> re.search(r'\bbar\b', 'foo bar baz') |
这几个示例中,则出现了两个\b
,其含义是要匹配在bar
两侧都能找到“位置”的字符串。
另外,\B
则是对\b
的取反。
1 | >>> print(re.search(r'\Bfoo\B', 'foo')) |
(未完,待续)
参考资料:https://realpython.com/regex-python/
搜索技术问答的公众号:老齐教室
在公众号中回复:老齐,可查看所有文章、书籍、课程。
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
关注微信公众号,读文章、听课程,提升技能