在上一篇(《Python正则表达式(一)》)中,已经介绍了正则表达式的基本含义,并且对re
模块中的元字符[ ]
进行了说明,本文接续上文,介绍有关元字符。
re
模块的元字符.
)点.
(注意必须是英文状态下的)是一个通配符,即表示了任何符号(换行符除外)。
>>> re.search('foo.bar', 'fooxbar')
<_sre.SRE_Match object; span=(0, 7), match='fooxbar'>
>>> print(re.search('foo.bar', 'foobar'))
None
>>> print(re.search('foo.bar', 'foo\nbar'))
None
在上面示例中,正则表达式foo.bar
表示的匹配规则是:先是三个字符foo
,然后用通配符.
说明第四个字符可以是除了换行符之外的任何字符,第五个及其后的字符是bar
。显然,fooxbar
符合这个规则,而foobar
和foo\nbar
不符合,前者foo
之后是b
,但b
之后是ar
而不是bar
;后者中间是一个换行符\n
。
\w
和\W
\w
匹配全部由字母和数字组成的字符串,即大写、小写字母以及0到9的数字,注意,也包括下划线。通常,也可以用[a-zA-Z0-9]
来替代它。
>>> re.search('\w', '#(.a$@&')
<_sre.SRE_Match object; span=(3, 4), match='a'>
>>> re.search('[a-zA-Z0-9_]', '#(.a$@&')
<_sre.SRE_Match object; span=(3, 4), match='a'>
显然,字符串'#(.a$@&'
中只有一个字母,上面演示中也都显示,匹配了字母a
。
如果是\W
(大写),则意味着与\w
相反,不包括字母、数字和下划线。
>>> re.search('\W', 'a_1*3Qb')
<_sre.SRE_Match object; span=(3, 4), match='*'>
>>> re.search('[^a-zA-Z0-9_]', 'a_1*3Qb')
<_sre.SRE_Match object; span=(3, 4), match='*'>
字符串'a_1*3Qb'
中的*
不属于字母、数字、下划线集合,在上述示例中匹配到了。注意,[^a-zA-Z0-9_]
中以^
开头,表示对后面字符集合的补集(取反)。
\d
和\D
\d
匹配由数字组成的字符,与[0-9]
相当。\D
同样是\d
取反,即[^0-9]
。
>>> re.search('\d', 'abc4def')
<_sre.SRE_Match object; span=(3, 4), match='4'>
>>> re.search('\D', '234Q678')
<_sre.SRE_Match object; span=(3, 4), match='Q'>
\s
和\S
\s
匹配任何空白字符,包括空格、制表符、换行符等等。等价于 [\f\n\r\t\v]
。
>>> re.search('\s', 'foo\nbar baz')
<_sre.SRE_Match object; span=(3, 4), match='\n'>
与前面一样,\S
也是对\s
取反,不匹配任何空白字符。
>>> re.search('\S', ' \n foo \n ')
<_sre.SRE_Match object; span=(4, 5), match='f'>
上面几个元字符,也可以写到一个集合中。
>>> re.search('[\d\w\s]', '---3---')
<_sre.SRE_Match object; span=(3, 4), match='3'>
>>> re.search('[\d\w\s]', '---a---')
<_sre.SRE_Match object; span=(3, 4), match='a'>
>>> re.search('[\d\w\s]', '--- ---')
<_sre.SRE_Match object; span=(3, 4), match=' '>
[\d\w\s]
的含义就是匹配任何数字、字母和空白字符,-
则不在匹配之列。
跟Python中的字符串中规定一样,在正则表达式中,也用\
表示对后面的字符转移。
>>> re.search('.', 'foo.bar')
<_sre.SRE_Match object; span=(0, 1), match='f'>
>>> re.search('\.', 'foo.bar')
<_sre.SRE_Match object; span=(3, 4), match='.'>
第一个示例中的.
,表示的是通配符,即任何字符。因此匹配了后面字符串中的第一个f
。第二个示例中的\.
,因为使用了转移符,它表示要匹配一个英文的句点,不再是通配符了,所以最终匹配了后面字符串中的句点符号。
使用\
,需要特别小心。
>>> s = r'foo\bar'
>>> print(s)
foo\bar
>>> s
'foo\\bar'
这里创立了原始字符串s
,注意,如果单单看print(s)
的结果,容易产生误解。因为这里使用了原始字符串r'foo\bar
,其中的\
就表示了原本的反斜杠符号,而不是转义符。当执行s
时,会看到,Python解析器会将其解析为'foo\\bar'
,也就是这种方式的字符串和前面定义的原始字符串是一样的,或者说前面定义原始字符串,在Python使用它的时候,会被解析为'foo\\bar'
,这就是我们要注意的地方。
下面要匹配s
里面的\
,按照通常方法,这样来试试:
>>> re.search('\\', s)
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
re.search('\\', s)
File "C:\Python36\lib\re.py", line 182, in search
return _compile(pattern, flags).search(string)
File "C:\Python36\lib\re.py", line 301, in _compile
p = sre_compile.compile(pattern, flags)
File "C:\Python36\lib\sre_compile.py", line 562, in compile
p = sre_parse.parse(p, flags)
File "C:\Python36\lib\sre_parse.py", line 848, in parse
source = Tokenizer(str)
File "C:\Python36\lib\sre_parse.py", line 231, in __init__
self.__next()
File "C:\Python36\lib\sre_parse.py", line 245, in __next
self.string, len(self.string) - 1) from None
sre_constants.error: bad escape (end of pattern) at position 0
出问题了,原因就在于Python解析器实际使用的是'foo\\bar'
,那么,这里就有了两个反斜杠,第一个反斜杠表示的是“转移符”,并把这个符号传给了re.search()
,正则表达式收到了单个反斜杠,但这不是有意义字符,因此会出现混乱,导致了错误。
下面演示两种解决方式:
>>> re.search('\\\\', s)
<_sre.SRE_Match object; span=(3, 4), match='\\'>
或者:
>>> re.search(r'\\', s)
<_sre.SRE_Match object; span=(3, 4), match='\\'>
定位字符是零宽度匹配,表示定位的符号不匹配字符串中的任何实际字符,并且不会使用任何搜索字符串。定位字符指示搜索字符串中必须发生匹配的特定位置。
^
或\A
^
或\A
表示匹配输入字符串的开始位置。但是,当它们在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合,即补集或相反。如果要匹配^
字符本身,必须要用\^
。
>>> re.search('^foo', 'foobar')
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> print(re.search('^foo', 'barfoo'))
None
正则表达式^foo
表示要匹配以foo
开头的字符串,'foobar'
符合规则,'barfoo'
不符合规则。
\A
的作用与^
一样。
>>> re.search('\Afoo', 'foobar')
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> print(re.search('\Afoo', 'barfoo'))
None
$
或\Z
与前述^
相对应,$
表示在字符串的结尾部分搜索相应匹配。
>>> re.search('bar$', 'foobar')
<_sre.SRE_Match object; span=(3, 6), match='bar'>
>>> print(re.search('bar$', 'barfoo'))
None
>>> re.search('bar\Z', 'foobar')
<_sre.SRE_Match object; span=(3, 6), match='bar'>
>>> print(re.search('bar\Z', 'barfoo'))
None
上面的示例中,bar$
表示搜索字符串结尾是bar
,foobar
符合此正则表达式的规则,barfoo
则不符合。在这里,\Z
与$
的效果一样。
但是,如果在下面的示例中,就只能使用$
。
>>> re.search('bar$', 'foobar\n')
<_sre.SRE_Match object; span=(3, 6), match='bar'>
\b
\b
匹配一个单词(也包括中文字符)的边界,即单词的分界。
例如这样一句话:Laoqi Classroom
,其中每个字符都有一个位置,包括空白(空格)也如此。如果某个字符后面的字符不是字母、数字和下划线,即不全是\w
所匹配的字符,那么\b
就会匹配后面的字符的后面(但不是下一个字符)。例如这句话中i
后面是空格,不在\w
范围内,那么\b
就会匹配空格后面、C
前面的位置。
例如:
>>> re.search(r'\bbar', 'foo bar')
<_sre.SRE_Match object; span=(4, 7), match='bar'>
>>> re.search(r'\bbar', 'foo.bar')
<_sre.SRE_Match object; span=(4, 7), match='bar'>
字符串foo bar
中有空格,正则表达式r'\bbar'
就匹配这个字符后面的位置,并且此位置之后是bar
。同理foo.bar
亦然。
但是:
>>> print(re.search(r'\bbar', 'foobar'))
None
则不然。因为foobar
本身没有\b
要匹配的位置。
>>> re.search(r'foo\b', 'foo bar')
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> re.search(r'foo\b', 'foo.bar')
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> print(re.search(r'foo\b', 'foobar'))
None
按照前述解释,上面示例不难理解。读者可以自己尝试梳理一番。
>>> re.search(r'\bbar\b', 'foo bar baz')
<_sre.SRE_Match object; span=(4, 7), match='bar'>
>>> re.search(r'\bbar\b', 'foo(bar)baz')
<_sre.SRE_Match object; span=(4, 7), match='bar'>
>>> print(re.search(r'\bbar\b', 'foobarbaz'))
None
这几个示例中,则出现了两个\b
,其含义是要匹配在bar
两侧都能找到“位置”的字符串。
另外,\B
则是对\b
的取反。
>>> print(re.search(r'\Bfoo\B', 'foo'))
None
>>> print(re.search(r'\Bfoo\B', '.foo.'))
None
>>> re.search(r'\Bfoo\B', 'barfoobaz')
<_sre.SRE_Match object; span=(3, 6), match='foo'>
(未完,待续)
参考资料:https://realpython.com/regex-python/