我已经编写了一个在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微秒,甚至更长时间才能完成.理解的速度更快.

推荐答案

请看Python manual -> re.findall

如果存在多个组,则返回与这些组匹配的字符串元组列表.非捕获组不影响结果的形式.

为了匹配所需的序列并防止匹配,例如这里的:00:a0:0a:.

res = re.findall(r":?\b(?:0\b:?)+", ip)

Python demo at tio.run.com/r/fhrhjD/1" rel="nofollow noreferrer">See this demo at regexPython demo at tio.runPython demo at tio.run

它匹配optional :后跟word boundary,再匹配repeated (?: non capturing group ) one or more times,repeated (?: non capturing group ) one or more timesword boundary处包含0,后跟optional冒号.

如果您不想匹配不带冒号的0,另一个变体:(?::0\b)+:?|(?:\b0:)+(?:0\b)?

Python相关问答推荐

如何将ctyles.POINTER(ctyles.c_float)转换为int?

连接两个具有不同标题的收件箱

使用groupby Pandas的一些操作

Pandas—合并数据帧,在公共列上保留非空值,在另一列上保留平均值

使用密钥字典重新配置嵌套字典密钥名

如何使用scipy的curve_fit与约束,其中拟合的曲线总是在观测值之下?

在Django admin中自动完成相关字段筛选

计算分布的标准差

如何保持服务器发送的事件连接活动?

不能使用Gekko方程'

matplotlib + python foor loop

交替字符串位置的正则表达式

干燥化与列姆化的比较

Numpyro AR(1)均值切换模型抽样不一致性

pandas fill和bfill基于另一列中的条件

如何在FastAPI中替换Pydantic的constr,以便在BaseModel之外使用?'

使用类型提示进行类型转换

如何获取包含`try`外部堆栈的`__traceback__`属性的异常

为什么我的scipy.optimize.minimize(method=";newton-cg";)函数停留在局部最大值上?

有什么方法可以在不对多索引DataFrame的列进行排序的情况下避免词法排序警告吗?