Python 正则匹配使用 match 匹配不完整

有个项目,使用自定义的表达式来表达时间长度,比如 1d 代表一天 , 3m2d4h8min299s 代表三个月两天四小时八分钟二百九十九秒。
现在考虑使用正则表达式来做格式的解析,
正则如下,使用命名分组方便取值。

'(?P<year>\d+(?=y))?(?P<month>\d+(?=m))?(?P<day>\d+(?=d))?(?P<hour>\d+(?=h))?(?P<minute>\d+(?=min))?(?P<second>\d+(?=s))?'

但是在测试的时候, 用 3d8s 做测试,
使用 re.match(regx, '3d8s').groupdict() 得到的结果是 {'hour': None, 'month': None, 'second': None, 'year': None, 'day': '3', 'minute': None}

用 re.findall(regx,'3d8s') 得到的是个列表,[('', '', '3', '', '', ''), ('', '', '', '', '', ''), ('', '', '', '', '', '8'), ('', '', '', '', '', ''), ('', '', '', '', '', '')]

这是因为什么?正确的做法是怎样的?

阅读 4.4k
3 个回答

(?=...)是不消耗这个字符的,而你应该消耗掉它。
m = re.match('((?P<year>\d+)y)?((?P<month>\d+)m(?!in))?((?P<day>\d+)d)?((?P<hour>\d+)h)?((?P<minute>\d+)min)?((?P<second>\d+)s)?', '8d3s')
谢楼下的m和min,再打补丁。

1.楼上是说的是对的。
2.引用别人的解释:"?=不同的人叫法不一样,你称之为预查,我更倾向于叫零宽断言,也就是说?=只是匹配一
个位置,并不匹配具体的字符,所以是零宽,也就是宽度是0。"
所以你这种匹配方式只能匹配到第一个,后面的就再也匹配不到了。你应该强制匹配后一个字母`((?
P<year>d+)y)?`。
3.而且你这么写还有一个问题:mmin

python3

import re

t = '3m2d4h8min299s'
ptn = (r'(?P<year>\d+(?=y))|'
       r'(?P<month>\d+(?=m(?!in)))|'
       r'(?P<day>\d+(?=d))|'
       r'(?P<hour>\d+(?=h))|'
       r'(?P<minute>\d+(?=min))|'
       r'(?P<second>\d+(?=s))')

print({k:int(v) for m in re.finditer(ptn, t)
                for k,v in m.groupdict().items()
                if v != None})

#{'hour': 4, 'second': 299, 'minute': 8, 'month': 3, 'day': 2}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题