检查字符串是否与某个模式匹配的最快方法是什么?正则表达式是最好的方法吗?
例如,我有一堆字符串,想要检查每一个字符串以查看它们是否是有效的IP地址(在这种情况下有效意味着正确的格式),是使用正则表达式执行此操作的最快方法吗?或者有更快的东西像字符串格式或其他东西。
这样的事情是我到目前为止所做的:
for st in strs:
if re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', st) != None:
print 'IP!'
答案 0 :(得分:71)
看起来你正试图validate IP addresses。正则表达式可能不是最好的工具。
如果您想接受所有有效的IP地址(包括您可能甚至不知道的某些地址有效),那么您可以使用IPy (Source):
from IPy import IP
IP('127.0.0.1')
如果IP地址无效,则会抛出异常。
或者你可以使用socket
(Source):
import socket
try:
socket.inet_aton(addr)
# legal
except socket.error:
# Not legal
如果你真的只想将IPv4与4个小数部分匹配,那么你可以在dot上分割并测试每个部分是0到255之间的整数。
def validate_ip(s):
a = s.split('.')
if len(a) != 4:
return False
for x in a:
if not x.isdigit():
return False
i = int(x)
if i < 0 or i > 255:
return False
return True
请注意,您的正则表达式不会执行此额外检查。它会接受999.999.999.999
作为有效地址。
答案 1 :(得分:14)
如果您使用 Python3 ,则可以使用ipaddress
模块http://docs.python.org/py3k/library/ipaddress.html。示例:
>>> import ipaddress
>>> ipv6 = "2001:0db8:0a0b:12f0:0000:0000:0000:0001"
>>> ipv4 = "192.168.2.10"
>>> ipv4invalid = "266.255.9.10"
>>> str = "Tay Tay"
>>> ipaddress.ip_address(ipv6)
IPv6Address('2001:db8:a0b:12f0::1')
>>> ipaddress.ip_address(ipv4)
IPv4Address('192.168.2.10')
>>> ipaddress.ip_address(ipv4invalid)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/lib/python3.4/ipaddress.py", line 54, in ip_address
address)
ValueError: '266.255.9.10' does not appear to be an IPv4 or IPv6 address
>>> ipaddress.ip_address(str)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/lib/python3.4/ipaddress.py", line 54, in ip_address
address)
ValueError: 'Tay Tay' does not appear to be an IPv4 or IPv6 address
答案 2 :(得分:13)
我通常是极少数坚持捍卫正则表达式的Python专家之一(他们在Python社区中声名狼借),但这不是其中之一 - 接受(比如说){{1因为“IP地址”真的不好,如果你需要在匹配RE之后做更多的检查,那么使用RE的大部分内容都会丢失。所以,我第二次@Mark的建议是:IPy一般性和优雅(如果你想要支持IPv6!),字符串操作和int检查,如果你只需要IPv4(但是,请三思而后行,然后再考虑再想一想 - IPv6的时间已经方式来了! - ):
'333.444.555.666'
我宁愿这样做而不是一个复杂的RE来匹配0到256之间的数字! - )
答案 3 :(得分:3)
再一次验证没有重新:
def validip(ip):
return ip.count('.') == 3 and all(0<=int(num)<256 for num in ip.rstrip().split('.'))
for i in ('123.233.42.12','3234.23.453.353','-2.23.24.234','1.2.3.4'):
print i,validip(i)
答案 4 :(得分:2)
您的正则表达式不检查字符串的结尾,因此它将匹配:
123.45.67.89abc123boogabooga
要解决此问题,请使用:
'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'
(注意最后的$
)。
最后,在Python中,通常的方式是使用is not None
而不是!= None
。
答案 5 :(得分:2)
如果您要验证IP地址,我会建议以下内容:
import socket
try:
socket.inet_aton(addr)
return True
except socket.error:
return False
如果您只是想检查它是否格式正确,那么您可能希望为所有legal bases(而不仅仅是基数10编号)执行此操作。
此外,仅IP地址是IPv4(并且没有IPv6),那么您可以查找有效地址并使用split()
(以获取IP的各个组件)和int()
(用于比较的种姓)。有效IPv4规则的快速参考是here。
答案 6 :(得分:2)
安装netaddr软件包
sudo pip install netaddr
然后你可以这样做
>>> from netaddr import valid_ipv4
>>> valid_ipv4('11.1.1.2')
True
>>> valid_ipv4('11.1.1.a')
False
此外,您还可以从该字符串创建一个IPAddress对象以及更多与ip相关的操作
>>> from netaddr import IPAddress
>>> ip = IPAddress('11.1.1.1')
>>> [f for f in dir(ip) if '__' not in f]
['_module', '_set_value', '_value', 'bin', 'bits', 'format', 'info', 'ipv4', 'ipv6', 'is_hostmask', 'is_ipv4_compat', 'is_ipv4_mapped', 'is_link_local', 'is_loopback', 'is_multicast', 'is_netmask', 'is_private', 'is_reserved', 'is_unicast', 'key', 'netmask_bits', 'packed', 'reverse_dns', 'sort_key', 'value', 'version', 'words']
答案 7 :(得分:1)
如果你反复使用,你应该预编译正则表达式
re_ip = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
# note the terminating $ to really match only the IPs
然后使用
if re_ip.match(st):
print '!IP'
但是...... '111.222.333.444'真的是IP?
我会查看netaddr
或ipaddr
个库是否可以用来匹配IP
答案 8 :(得分:1)
我们不需要任何导入来执行此操作。这也可以更快地运行
def is_valid_ip(str_ip_addr):
"""
:return: returns true if IP is valid, else returns False
"""
ip_blocks = str(str_ip_addr).split(".")
if len(ip_blocks) == 4:
for block in ip_blocks:
# Check if number is digit, if not checked before calling this function
if not block.isdigit():
return False
tmp = int(block)
if 0 > tmp > 255:
return False
return True
return False
答案 9 :(得分:1)
此页面中的其他正则表达式答案将接受数字超过255的IP。
这个正则表达式可以避免这个问题:
import re
def validate_ip(ip_str):
reg = r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
if re.match(reg, ip_str):
return True
else:
return False
答案 10 :(得分:0)
可以使用iptools。
import iptools
ipv4 = '1.1.1.1'
ipv6 = '5000::1'
iptools.ipv4.validate_ip(ipv4) #returns bool
iptools.ipv6.validate_ip(ipv6) #returns bool
答案 11 :(得分:0)
您可以尝试以下方法(该程序可以进一步优化):
path = "/abc/test1.txt"
fh = open (path, 'r')
ip_arr_tmp = []
ip_arr = []
ip_arr_invalid = []
for lines in fh.readlines():
resp = re.search ("([0-9]+).([0-9]+).([0-9]+).([0-9]+)", lines)
print resp
if resp != None:
(p1,p2,p3,p4) = [resp.group(1), resp.group(2), resp.group(3), resp.group(4)]
if (int(p1) < 0 or int(p2) < 0 or int(p3) < 0 or int(p4) <0):
ip_arr_invalid.append("%s.%s.%s.%s" %(p1,p2,p3,p4))
elif (int(p1) > 255 or int(p2) > 255 or int(p3) > 255 or int(p4) > 255):
ip_arr_invalid.append("%s.%s.%s.%s" %(p1,p2,p3,p4))
elif (len(p1)>3 or len(p2)>3 or len(p3)>3 or len(p4)>3):
ip_arr_invalid.append("%s.%s.%s.%s" %(p1,p2,p3,p4))
else:
ip = ("%s.%s.%s.%s" %(p1,p2,p3,p4))
ip_arr_tmp.append(ip)
print ip_arr_tmp
for item in ip_arr_tmp:
if not item in ip_arr:
ip_arr.append(item)
print ip_arr
答案 12 :(得分:0)
在Python 3.6上我觉得更简单,因为已经包含了ipaddress模块:
import ipaddress
def is_ipv4(string):
try:
ipaddress.IPv4Network(string)
return True
except ValueError:
return False
答案 13 :(得分:0)
#!/usr/bin/python
import sys
def check_ip(address):
part=address.split(".")
temp=True
if len(part) != 4:
temp=False
return temp
for p in part:
if not 0<= int(p) <= 255:
temp=False
return temp
else:
temp=True
return temp
if __name__=="__main__":
print check_ip(sys.argv[1])
使用某个名称保存代码 - check_ip.py
并将其作为python check_ip.py 192.168.560.25
运行
注意: - 以上代码针对以下IP地址失败 -
023.65.029.33
答案 14 :(得分:0)
这也适用于ipv6地址。
不幸的是它仅适用于python3
import ipaddress
def valid_ip(address):
try:
print ipaddress.ip_address(address)
return True
except:
return False
print valid_ip('10.10.20.30')
print valid_ip('2001:DB8::1')
print valid_ip('gibberish')
答案 15 :(得分:0)
使用内置库 ipaddress 检查给定IP是否有效非常简单。您也可以使用掩码值进行验证。
ip = '30.0.0.1' #valid
#ip = '300.0.0.0/8' #invalid
#ip = '30.0.0.0/8' #valid
#ip = '30.0.0.1/8' #invalid
#ip = 'fc00:da00::3402:69b1' #valid
#ip = 'fc00:da00::3402:69b1/128' #valid
#ip = 'fc00:da00::3402:69b1:33333' #invalid
if ip.find('/') > 0:
try:
temp2 = ipaddress.ip_network(ip)
print('Valid IP network')
except ValueError:
print('Invalid IP network, value error')
else:
try:
temp2 = ipaddress.ip_address(ip)
print('Valid IP')
except ValueError:
print('Invalid IP')
注意:在Python 3.4.3中测试
答案 16 :(得分:0)
我作弊并使用了其他人提交的多个答案的组合。我认为这是非常明确和直接的代码。 ip_validation
应该返回True
或False
。此答案仅适用于IPv4地址
import re
ip_match = re.match('^' + '[\.]'.join(['(\d{1,3})']*4) + '$', ip_input)
ip_validate = bool(ip_match)
if ip_validate:
ip_validate &= all(map(lambda n: 0 <= int(n) <= 255, ip_match.groups())
答案 17 :(得分:0)
你可以通过编译来加快它的速度:
expression = re.compile('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
for st in strs:
if expression.match(st):
print 'IP!'
答案 18 :(得分:-1)