我已经编写了一个在IPv6地址与int
地址之间来回转换的小程序,并且在性能方面超过了内置ipaddress.IPv6Address
.
import re
MAX_IPV6 = 2**128-1
DIGITS = set("0123456789abcdef")
def parse_ipv6(ip: str) -> int:
assert isinstance(ip, str) and len(ip) <= 39
segments = ip.lower().split(":")
l, n, p, count, compressed = len(segments), 0, 7, 0, False
last = l - 1
for i, s in enumerate(segments):
assert count <= 8 and len(s) <= 4 and not set(s) - DIGITS
if not s:
if i in (0, last):
continue
assert not compressed
p = l - i - 2
compressed = True
else:
n += int(s, 16) << p*16
p -= 1
count += 1
return n
def to_ipv6(n: int, compress=False) -> str:
assert isinstance(n, int) and 0 <= n <= MAX_IPV6
ip = '{:032_x}'.format(n).replace('_', ':')
if not compress:
return ip
return re.sub('0{1,3}([\da-f]+)', '\\1', ip)
我目前正在try 实现压缩,即找到两个交替字符0和:的最长游程,并将第一个出现的字符替换为::.
例如,给定地址:'abcd:0:ef12::a:0:0'
,parse_ipv6('abcd:0:ef12::a:0:0')
表示该数字:228362408209208931942454293848746098688
,而to_ipv6(parse_ipv6('abcd:0:ef12::a:0:0'), 1)
表示该数字:'abcd:0:ef12:0:0:a:0:0'
.
如您所见,结果没有正确压缩.
简而言之,我希望对re.findall
使用正则表达式模式来查找像[':0', ':0:', ':0:0:', '0:', '0:0:', '0:0:0:']
这样的序列.
我用谷歌搜索了一下,在这个网站上发现了很多类似措辞的问题,但没有一个能解决我的问题.
我试过这个正则表达式:
In [277]: ip
Out[277]: 'abcd:0:ef12:0:0:a:0:0'
In [278]: re.findall('((:0)+)|((0:)+)', ip)
Out[278]: [(':0', ':0', '', ''), (':0:0', ':0', '', ''), (':0:0', ':0', '', '')]
我还以为有[':0:', ':0:0:', ':0:0']
个呢.
如何解决这个问题?
使用正确的正则表达式,我将代码更新为:
EMPTY = re.compile(r':?\b(?:0\b:?)+')
def to_ipv6(n: int, compress:bool=False) -> str:
assert isinstance(n, int) and 0 <= n <= MAX_IPV6
ip = '{:032_x}'.format(n).replace('_', ':')
if not compress:
return ip
ip = ':'.join(s.lstrip('0') if s != '0000' else '0' for s in ip.split(':'))
longest = max(EMPTY.findall(ip))
if len(longest) > 2:
ip = ip.replace(longest, '::', 1)
return ip
它正确地压缩了给定的示例:
In [334]: to_ipv6(228362408209208931942454293848746098688, True)
Out[334]: 'abcd:0:ef12::a:0:0'
我停止使用re.sub('0{1,3}([\da-f]+)', '\\1', ip)
,因为不知何故,它需要8微秒,甚至更长时间才能完成.理解的速度更快.