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

python">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字符?


回答:

请问为什么第一行可以匹配到一个hex,二三行却匹配到一个空字符?
  • (%[0-9a-fA-F]{2}) 的意思是“% 后面跟着两个范围内的数字或字母,且只匹配一次”;
  • re.search 只返回从左到右第一个匹配的对象
  • * 表示匹配零次或多次

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

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

如果使用 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 正则表达式。

以上是 关于python正则re.search匹配的困惑 的全部内容, 来源链接: utcz.com/p/937885.html

回到顶部