前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python中的正则表达式(二)

Python中的正则表达式(二)

作者头像
老齐
发布2020-05-14 20:38:41
5670
发布2020-05-14 20:38:41
举报
文章被收录于专栏:老齐教室

在上一篇(《Python正则表达式(一)》)中,已经介绍了正则表达式的基本含义,并且对re模块中的元字符[ ]进行了说明,本文接续上文,介绍有关元字符。

re模块的元字符

点(.

.(注意必须是英文状态下的)是一个通配符,即表示了任何符号(换行符除外)。

代码语言:javascript
复制
>>> 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符合这个规则,而foobarfoo\nbar不符合,前者foo之后是b,但b之后是ar而不是bar;后者中间是一个换行符\n

\w\W

\w匹配全部由字母和数字组成的字符串,即大写、小写字母以及0到9的数字,注意,也包括下划线。通常,也可以用[a-zA-Z0-9]来替代它。

代码语言:javascript
复制
>>> 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相反,不包括字母、数字和下划线。

代码语言:javascript
复制
>>> 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]

代码语言:javascript
复制
>>> 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]

代码语言:javascript
复制
>>> re.search('\s', 'foo\nbar baz')
<_sre.SRE_Match object; span=(3, 4), match='\n'>

与前面一样,\S也是对\s取反,不匹配任何空白字符。

代码语言:javascript
复制
>>> re.search('\S', '  \n foo  \n  ')
<_sre.SRE_Match object; span=(4, 5), match='f'>

上面几个元字符,也可以写到一个集合中。

代码语言:javascript
复制
>>> 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中的字符串中规定一样,在正则表达式中,也用\表示对后面的字符转移。

代码语言:javascript
复制
>>> 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。第二个示例中的\.,因为使用了转移符,它表示要匹配一个英文的句点,不再是通配符了,所以最终匹配了后面字符串中的句点符号。

使用\,需要特别小心。

代码语言:javascript
复制
>>> 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里面的\,按照通常方法,这样来试试:

代码语言:javascript
复制
>>> 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(),正则表达式收到了单个反斜杠,但这不是有意义字符,因此会出现混乱,导致了错误。

下面演示两种解决方式:

代码语言:javascript
复制
>>> re.search('\\\\', s)
<_sre.SRE_Match object; span=(3, 4), match='\\'>

或者:

代码语言:javascript
复制
>>> re.search(r'\\', s)
<_sre.SRE_Match object; span=(3, 4), match='\\'>

定位字符

定位字符是零宽度匹配,表示定位的符号不匹配字符串中的任何实际字符,并且不会使用任何搜索字符串。定位字符指示搜索字符串中必须发生匹配的特定位置。

^\A

^\A表示匹配输入字符串的开始位置。但是,当它们在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合,即补集或相反。如果要匹配^字符本身,必须要用\^

代码语言:javascript
复制
>>> re.search('^foo', 'foobar')
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> print(re.search('^foo', 'barfoo'))
None

正则表达式^foo表示要匹配以foo开头的字符串,'foobar'符合规则,'barfoo'不符合规则。

\A的作用与^一样。

代码语言:javascript
复制
>>> re.search('\Afoo', 'foobar')
<_sre.SRE_Match object; span=(0, 3), match='foo'>
>>> print(re.search('\Afoo', 'barfoo'))
None

$\Z

与前述^相对应,$表示在字符串的结尾部分搜索相应匹配。

代码语言:javascript
复制
>>> 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$表示搜索字符串结尾是barfoobar符合此正则表达式的规则,barfoo则不符合。在这里,\Z$的效果一样。

但是,如果在下面的示例中,就只能使用$

代码语言:javascript
复制
>>> re.search('bar$', 'foobar\n')
<_sre.SRE_Match object; span=(3, 6), match='bar'>

\b

\b匹配一个单词(也包括中文字符)的边界,即单词的分界。

例如这样一句话:Laoqi Classroom,其中每个字符都有一个位置,包括空白(空格)也如此。如果某个字符后面的字符不是字母、数字和下划线,即不全是\w所匹配的字符,那么\b就会匹配后面的字符的后面(但不是下一个字符)。例如这句话中i后面是空格,不在\w范围内,那么\b就会匹配空格后面、C前面的位置。

例如:

代码语言:javascript
复制
>>> 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亦然。

但是:

代码语言:javascript
复制
>>> print(re.search(r'\bbar', 'foobar'))
None

则不然。因为foobar本身没有\b要匹配的位置。

代码语言:javascript
复制
>>> 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

按照前述解释,上面示例不难理解。读者可以自己尝试梳理一番。

代码语言:javascript
复制
>>> 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的取反。

代码语言:javascript
复制
>>> 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/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老齐教室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • re模块的元字符
    • 点(.)
      • \w和\W
        • \d和\D
          • \s和\S
          • 转义符
          • 定位字符
            • ^或\A
              • $或\Z
                • \b
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档