在我的代码中,我想回答[('22', '254', '15', '36')]
但得到[('15', '36')]
。我的正则表达式(?:([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)\.){3}
可能不会运行3次!
import re
def fun(st):
print(re.findall("(?:([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)\.){3}([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)",st))
ip="22.254.15.36"
print(fun(ip))
答案 0 :(得分:1)
你的正则表达式中只有两个捕获组:
(?: # non-capturing group
( # group 1
[0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?
)\.
){3}
( # group 2
[0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?
)
第一组可重复3次并不会使其捕获3次。正则表达式引擎只会返回2个组,并且给定组中的最后一个匹配将填充该组。
如果要将IP地址的每个部分捕获到不同的组中,则必须为每个部分明确定义组:
pattern = (
r'([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)\.'
r'([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)\.'
r'([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)\.'
r'([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)')
def fun(st, p=re.compile(pattern)):
return p.findall(st)
你可以通过一些字符串和列表操作避免那么多的重复:
octet = r'([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)'
pattern = r'\.'.join([octet] * 4)
接下来,该模式将与25
的{{1}}部分愉快地匹配。最好将200-255范围的匹配在开头匹配较小的数字:
255
顺便提一下,这仍然允许前导octet = r'(2(?:5[0-5]|[0-4]\d)|[01]?[0-9]{1,2})'
pattern = r'\.'.join([octet] * 4)
个数字,但是
如果你所做的只是传入单个IP地址,那么0
就是过度杀手,只需使用re.findall()
(仅匹配字符串开头)或p.match()
,然后返回{ {1}}如果匹配则会产生结果;)
p.search()
请注意,未对周围数据进行验证,因此,如果您尝试从更大的文本中提取IP地址,则无法使用.groups()
,并且无法添加{{1} } anchor和匹配可以来自更大数量的八位字节(例如22.22.22.22.22.22)。您必须为此添加一些环视操作符:
def fun(st, p=re.compile(pattern + '$')):
match = p.match(st)
return match and match.groups()
答案 1 :(得分:1)
正如我在下面的评论中提到的那样,大多数正则表达式引擎只捕获最后一个匹配。因此,当您执行(...){3}
时,仅捕获最后一场比赛:例如用于(.){3}
的{{1}}只会返回abc
。
另外,请注意,将正则表达式更改为c
的效果要好得多,并且会捕获完整的数字(例如,您最后会在最后一个八位字节中抓取(2[0-4]\d|25[0-5]|[01]?\d{1,2})
而不是25
- 除非您将它锚定到最后)。
为您提供一个功能齐全的正则表达式来捕获IP的每个八位字节:
255
然而,就个人而言,我将逻辑与验证分开。下面的代码首先验证字符串的格式,然后在(2[0-4]\d|25[0-5]|[01]?\d{1,2})\.(2[0-4]\d|25[0-5]|[01]?\d{1,2})\.(2[0-4]\d|25[0-5]|[01]?\d{1,2})\.(2[0-4]\d|25[0-5]|[01]?\d{1,2})
上分割字符串时检查逻辑(没有大于255的八位字节)是否通过。
.
结果:import re
ip='22.254.15.36'
if re.match(r"(?:\d{1,3}\.){3}\d{1,3}$", ip):
print([octet for octet in ip.split('.') if int(octet) < 256])
如果您使用此方法从任意字符串中提取IP,则可以将['22', '254', '15', '36']
替换为re.match()
或re.search()
。在这种情况下,您可能需要删除re.findall()
并添加一些逻辑,以确保您不匹配$
之类的特殊情况:11.11.11.11.11
答案 2 :(得分:0)
我遇到了非常相似的问题。 我使用官方文档找到了两种解决方案。 上面@ctwheels的答案确实提到了该问题的原因,我对此表示感谢,但它没有提供解决方案。 即使尝试向后看和向后看,它也不起作用。
re.finditer 遍历匹配对象!
您可以使用每个人的“分组”方法!
>>> def fun(st):
pr=re.finditer("(?:([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)\.){3}([0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)",st)
for p in pr:
print(p.group(),end="")
>>> fun(ip)
22.254.15.36
或者!!!
“ re.findall:
...如果模式中存在一个或多个组,则返回组列表”
(Python 3.8手册)
所以:
>>> def fun(st):
print(re.findall("(?:(?:[0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)\.){3}(?:[0-1]?[0-9]{0,2}|2?[0-4]?[0-9]|25[0-5]?)",st))
>>> fun(ip)
['22.254.15.36']
玩得开心!