python正则表达式的贪婪匹配

今天在工作过程中用到正则表达式。先说一下我的需求,给这样一个句子:

今天我和李白(Li Bai)一起去吃饭,路上碰到了露娜(luna),他俩打起来了。

我希望将句子中括号和括号里的内容删掉。这个需求可以通过 re.sub() 函数来实现。先介绍一下这个函数:

原型:rb.sub(pattern, repl, string, count=0, flags=0)

功能:将string中出现的可以匹配pattern的内容用repl替换。count用来限制替换的子串数量。

现在我们来尝试一下:

>>> import re
>>> s = '今天我和李白(Li Bai)一起去吃饭,路上碰到了露娜(luna),他俩打起来了。'
>>> re.sub("\(.*\)", "", s)
'今天我和李白,他俩打起来了。'

很明显,结果和我们想要的不一样,这就是因为正则表达式匹配默认是贪婪模式。什么是贪婪模式?就是它的匹配结果会尽可能长,在例子中,我们的正则表达式 "\(.*\)" 目标是匹配以"("开头")"结尾的子串,(Li Bai)和(Li Bai)一起去吃饭,路上碰到了露娜(luna)这两个子串都符合要求,那么它就会默认选择长的,这就出现了我们刚才看到的结果。

可是我不想要这个结果,我想用非贪婪模式:让左括号匹配到离它最近的右括号。很简单,一个 就可以搞定!在"\(.*\)" 中,.*代表匹配任意长度的任意字符,我们在它后面加个?,再来试试看:

>>> import re
>>> s = '今天我和李白(Li Bai)一起去吃饭,路上碰到了露娜(luna),他俩打起来了。'
>>> re.sub("\(.*?\)", '', s)
'今天我和李白一起去吃饭,路上碰到了露娜,他俩打起来了。'

漂亮!这就是我们想要的结果。

非贪婪模式在什么情况下奏效呢?我们用 'www.baidu.com' 再来试试,用re.match()函数来搜索匹配子串,结果看起来会更直观一些:

import re

s = 'www.baidu.com'

# 1.搜索单个字符时无效
print("re.match('.', s): ", end='')
tmp = re.match('.', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.', s): w
print("re.match('.?', s): ", end='')
tmp = re.match('.?', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.?', s): w


# 2. 搜索固定长度字符串无效
print("re.match('.{2}', s): ", end='')
tmp = re.match('.{2}', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.{2}', s): ww
print("re.match('.{2}?', s): ", end='')
tmp = re.match('.{2}?', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.{2}?', s): ww

# 3. 搜索限制长度的字符串有效
print("re.match('.{5,8}', s): ", end='')
tmp = re.match('.{5,8}', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.{5,8}', s): www.baid
print("re.match('.{5,8}?', s): ", end='')
tmp = re.match('.{5,8}?', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.{5,8}?', s): www.b

# 4. 搜索任意长度字符串有效
print("re.match('.*', s): ", end='')
tmp = re.match('.*', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.*', s): www.baidu.com
print("re.match('.*?', s): ", end='')
tmp = re.match('.*?', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.*?', s):

# 5. 搜索长度>=1的字符串有效
print("re.match('.+', s): ", end='')
tmp = re.match('.+', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.+', s): www.baidu.com
print("re.match('.+?', s): ", end='')
tmp = re.match('.+?', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('.+?', s): w

# 6. 匹配某一字符0~1次
print("re.match('w?', s): ", end='')
tmp = re.match('w?', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('w?', s): w
print("re.match('w??', s): ", end='')
tmp = re.match('w??', s).span()
print(s[tmp[0]:tmp[1]])                                # re.match('w??', s): 

综上所述,在以下几种情况下非贪婪匹配可以发挥出它的作用:

*?: 匹配0到任意多个字符;

+?: 匹配一个到任意多个字符;

{m, n}?: 最少匹配m个,最多匹配n个字符;

??: 匹配0~1个;

总结:

python的正则表达式匹配时默认是贪婪模式的,贪婪模式下会匹配到符合正则表达式的最长的字符串;如果想用非贪婪模式,加个?

推荐一个正则表达式学习网址:https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值