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

Python中的正则表达式(五)

作者头像
老齐
发布2020-05-26 10:10:41
7960
发布2020-05-26 10:10:41
举报
文章被收录于专栏:老齐教室老齐教室

其他分组

分组的形式多种多样,以上简要介绍了几种最基本的,在上述内容基础上,可以进一步探讨其他分组形式。

(?P<name><regex>)

在前面的操作中,如果有多个正则表达式分组,可以用从1开始(注意不是从0开始)的需要,获得相应分组捕获的对象。例如:

代码语言:javascript
复制
>>> m = re.search('(\w+),(\w+),(\w+)', 'foo,quux,baz')
>>> m.groups()
('foo', 'quux', 'baz')

>>> m.group(1, 2, 3)
('foo', 'quux', 'baz')

此外,为了意义更明确,我们也可以用(?P<name><regex>)方式,给每个分组命名,之后通过命名得到每组捕获的对象。

代码语言:javascript
复制
>>> m = re.search('(?P<w1>\w+),(?P<w2>\w+),(?P<w3>\w+)', 'foo,quux,baz')
>>> m.groups()
('foo', 'quux', 'baz')

以上为每个分组分别命名为w1w2w3m.groups()的执行结果没有变化。重点看下面操作:

代码语言:javascript
复制
>>> m.group('w1')
'foo'
>>> m.group('w3')
'baz'
>>> m.group('w1', 'w2', 'w3')
('foo', 'quux', 'baz')

这样,通过分组的名称,得到了相应分组捕获的对象。

有了分组名称的命名之后,原有序号依然有效,你可以混合使用。

代码语言:javascript
复制
>>> m = re.search('(?P<w1>\w+),(?P<w2>\w+),(?P<w3>\w+)', 'foo,quux,baz')

>>> m.group('w1')
'foo'
>>> m.group(1)
'foo'

>>> m.group('w1', 'w2', 'w3')
('foo', 'quux', 'baz')
>>> m.group(1, 2, 3)
('foo', 'quux', 'baz')

(?P=<name>)

(?P=<name>)匹配向后引用的字符串,类似\<n>,但是这里给出了名称。例如:

代码语言:javascript
复制
>>> m = re.search(r'(\w+),\1', 'foo,foo')
>>> m
<_sre.SRE_Match object; span=(0, 7), match='foo,foo'>
>>> m.group(1)
'foo'

这是前面已经熟悉的\<n>模式,如果按照序号,可以捕获向后引用所对应的字符。

同样的操作,下面对分组命名,然后用(?P=<name>)模式向后引用。

代码语言:javascript
复制
>>> m = re.search(r'(?P<word>\w+),(?P=word)', 'foo,foo')
>>> m
<_sre.SRE_Match object; span=(0, 7), match='foo,foo'>
>>> m.group('word')
'foo'

(?P=<word>\w+)匹配字符串'foo',并将它保存为word这个命名的捕获,然后,逗号后面表示的向后引用(?P=word),再次匹配和捕获一个字符串'foo'

注意在向后引用的那部分分组命名的写法,不要在名称外面用尖括号包裹。

代码语言:javascript
复制
>>> m = re.match(r'(?P<num>\d+)\.(?P=num)', '135.135')
>>> m
<_sre.SRE_Match object; span=(0, 7), match='135.135'>

>>> m.group('num')
'135'

(?:<regex>)

(?:<regex>)(<regex>)类似,都是在<regex>中指定匹配的正则表达式,但是(?:<regex>)不会捕获所匹配的字符,以后也无法检索到。

代码语言:javascript
复制
>>> m = re.search('(\w+),(?:\w+),(\w+)', 'foo,quux,baz')
>>> m.groups()
('foo', 'baz')

>>> m.group(1)
'foo'
>>> m.group(2)
'baz'

在上面的示例中,中间的字符串quux就没有被捕获,与它对应的就会前面正表达式中的(?:\w+)

根据条件匹配

根据条件匹配的方式有两种:

  • (?(<n>)<yes-regex>|<no-regex>):如果存在<n>,则匹配<yes-regex>,否则,它将匹配<no-regex>
  • (?(<name>)<yes-regex>|<no-regex>):如果存在<name>,则匹配<yes-regex>,否则,它将匹配<no-regex>

例如:

代码语言:javascript
复制
regex = r'^(###)?foo(?(1)bar|baz)'

这个正则表达式示例,含义为:

  • ^(###)?表示要匹配以###开头的字符串,如果找到,就根据###的分组括号创建编号为1的组。否则,不存在改组。
  • 后面的foo,表示匹配字符串中的foo
  • 最后,(?(1)bar|baz),如果组1存在,就匹配bar,否则baz

将上面的正则表达式用在下面的示例中。

代码语言:javascript
复制
>>> re.search(regex, '###foobar')
<_sre.SRE_Match object; span=(0, 9), match='###foobar'>

###foobar是以###开头,因此创建组1,然后匹配bar,字符串中也有此匹配对象,最后返回匹配结果。

代码语言:javascript
复制
>>> print(re.search(regex, '###foobaz'))
None

###foobar是以###开头,因此创建组1,然后匹配bar,但是,字符串中后面是baz,没有匹配成功,最后返回None

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

foobar不是###开头,没有创建组1,根据条件,就要匹配baz,但字符串中是bar,所以返回None

代码语言:javascript
复制
>>> re.search(regex, 'foobaz')
<_sre.SRE_Match object; span=(0, 6), match='foobaz'>

foobar不是###开头,没有创建组1,根据条件,就要匹配baz,字符串中后面恰好是bar

下面的正则表达式,与上面不同之处在于,对所创建的组进行了命名。

代码语言:javascript
复制
>>> regex = r'^(?P<ch>\W)?foo(?(ch)(?P=ch)|)$'

将这个正则表达式分解,并说明其含义:

  • ^:字符串的开始
  • (?P<ch>\W):匹配一个非字母字符,并将改组捕获对象命名为ch
  • (?P<ch>\W)?:以上情况,匹配0个或1个。
  • foo:匹配字符串foo
  • (?(ch)(?P=ch)|):如果ch的组存在,匹配的内容和ch组一样,否则为空。
  • $:字符串的结尾

如果非字母字符位于foo之前,则解析器创建一个名为ch的组,其中包含该字符。然后,条件匹配匹配<yes-regex>,它是(?P=ch),还是同样的字符。这意味着相同的字符也必须跟在foo后面,这样整个匹配才会成功。

如果foo前面没有非字母字符,那么解析器就不会创建ch组,<no-regex>是空字符串,这意味着在foo后面必须没有任何内容,整个匹配才会成功。因为^$锚定整个正则表达式,所以字符串必须恰好等于foo

通过下面示例,进一步演示上述正则表达式的应用:

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

>>> re.search(regex, '#foo#')
<_sre.SRE_Match object; span=(0, 5), match='#foo#'>

>>> re.search(regex, '@foo@')
<_sre.SRE_Match object; span=(0, 5), match='@foo@'>

>>> print(re.search(regex, '#foo'))
None

>>> print(re.search(regex, 'foo@'))
None

>>> print(re.search(regex, '#foo@'))
None

>>> print(re.search(regex, '@foo#'))
None

比照前面的解释,理解上述操作结果。

Python中条件正则表达式有点深奥和具有挑战性的,替代它的一个方法,就是使用多个单独的re.search()调用来实现相同的目标,这样代码就不会那么复杂了。

(未完,待续)

参考资料:https://realpython.com/regex-python/

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • (?P<name><regex>)
  • (?P=<name>)
  • (?:<regex>)
  • 根据条件匹配
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档