关于python正则re.search匹配的困惑

发布于 2022-09-12 13:19:21 字数 416 浏览 13 评论 0

re.search(r'(%[0-9a-fA-F]{2})', r'自定:%E8%87%AA%E5%AE%9A%E5')
# '%E8'
re.search(r'(%[0-9a-fA-F]{2})*', r'自定:%E8%87%AA%E5%AE%9A%E5')
# ''
re.search(r'((%[0-9a-fA-F]{2})*)', r'自定:%E8%87%AA%E5%AE%9A%E5')
# ''
re.search(r'(?<=:)((%[0-9a-fA-F]{2})*)', r'自定:%E8%87%AA%E5%AE%9A%E5')
# '%E8%87%AA%E5%AE%9A%E5'

请问为什么第一行可以匹配到一个hex,二三行却匹配到一个空字符?
为什么第四行设定了前方是一个:后,又匹配到了全部的hex字符?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

司马昭之心 2022-09-19 13:19:21

请问为什么第一行可以匹配到一个hex,二三行却匹配到一个空字符?

  • (%[0-9a-fA-F]{2}) 的意思是“% 后面跟着两个范围内的数字或字母,且只匹配一次”;
  • re.search 只返回从左到右第一个匹配的对象
  • * 表示匹配零次或多次

所以第一行可以匹配到字符串最左边的 %E8,而且只匹配到一个。而第二、三行由于 * 的存在,第一个匹配到的是最左边的空字符,所以返回的是 ''

image.png

如果使用 re.finditer() 就可以看到第二、三行是都可以匹配到全部的(%E8%87%AA%E5%AE%9A%E5)。进一步,如果直接将第二行的 * 改为 +,即匹配 1 次或多次,就会返回你想要的全部 hex:

>>> matches = re.finditer(r'(%[0-9a-fA-F]{2})*', r'自定:%E8%87%AA%E5%AE%9A%E5')
>>> for m in matches:
...     print(m)
...
<re.Match object; span=(0, 0), match=''>
<re.Match object; span=(1, 1), match=''>
<re.Match object; span=(2, 2), match=''>
<re.Match object; span=(3, 24), match='%E8%87%AA%E5%AE%9A%E5'>
<re.Match object; span=(24, 24), match=''>
>>> re.search(r'(%[0-9a-fA-F]{2})+', r'自定:%E8%87%AA%E5%AE%9A%E5')
<re.Match object; span=(3, 24), match='%E8%87%AA%E5%AE%9A%E5'>

为什么第四行设定了前方是一个:后,又匹配到了全部的hex字符?

?< 这个东西叫后行断言lookbehind assertion),小于号 < 表示箭头方向左向,即“回头看”。后面的 =: 就是表面意思,等于 :。综合起来就是“左边的字符是 :”。

所以 (?<=:)((%[0-9a-fA-F]{2})*) 的意思就是“匹配左边是 :,且符合 % 后面跟着两个范围内的数字或字母的模式的字符串,匹配零次或多次”。那既然有 * 的存在,为什么不会像第二、三行一样匹配到最左边的空字符呢?因为他们左边不是 :

所以你想匹配到所有 hex 字符,最简单的就是把第二行的 * 改为 +(%[0-9a-fA-F]{2})+。而第四行显然是有点多余了。

关于更多正则表达式的内容,例如先行断言和后行断言等,可以参见我的文章:SLP3:2.1 正则表达式

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文