’:’分字符串形式的ipv6地址和10进制形式的ipv6地址之间相互转换实现

# -*- coding: UTF-8 -*-
import socket
import ipaddress
from binascii import hexlify


def convert_ipv6_to_int(ipv6_addr):
    """
    convert_ipv6_to_int: 将:分字符串形式的ipv6地址转换为10进制形式的ipv6地址
    :param ipv6_addr ipv6 address, string
    :return integer ipv6 address
    """
    return int(hexlify(socket.inet_pton(socket.AF_INET6, ipv6_addr)), 16)


def convert_int_to_ipv6(ipv6_int):
    """
    convert_int_to_ipv6: 将10进制格式的ipv6地址转换为极简大写字符串格式的ipv6地址
    :param ipv6_int 10进制数字格式的ipv6地址
    :return [error, ipv6_addr] ipv6_addr 为极简大写字符串格式的ipv6地址
    """
    ipv6_addr = ''
    index = 0
    while ipv6_int > 0:
        index += 1
        ipv6_addr = hex(ipv6_int % 16)[2] + ipv6_addr
        ipv6_int = ipv6_int >> 4
        if (index % 4 == 0) and (index != 32):
            ipv6_addr = ':' + ipv6_addr

    while index < 32:
        index += 1
        ipv6_addr = '0' + ipv6_addr
        if (index % 4 == 0) and (index != 32):
            ipv6_addr = ':' + ipv6_addr

    try:
        ipv6_obj = ipaddress.IPv6Address(unicode(ipv6_addr))
    except Exception as e:
        error = 'illegal ipv6 addr, ipv6_int: %d, ipv6_addr: %s, error: %s' % (ipv6_int, ipv6_addr, e)
        return error, None
    return None, ipv6_obj.compressed.upper()


def test_convert_int_to_ipv6():
    """
    test_convert_int_to_ipv6: 测试函数convert_int_to_ipv6
    """
    test_cases = [
        '::',
        '::f',
        '::1',
        '::0',
        '0a::',
        'a0::',
        'fe80:0000:0000:0000:021b:77ff:fbd6:7860',
        'fe80::021b:77ff:fbd6:7860',
        'fe80::21b:77ff:fbd6:7860',
        'fe80::fbd6:7860'
    ]
    for case in test_cases:
        ipv6_int = convert_ipv6_to_int(case)
        error, ipv6_addr_result = convert_int_to_ipv6(ipv6_int)
        if not (error is None):
            print error
            continue
        ipv6_addr_target = ipaddress.IPv6Address(unicode(case)).compressed.upper()
        if ipv6_addr_result != ipv6_addr_target:
            print 'error, case: %s, ipv6_int: %d, ipv6_addr_result: %s, ipv6_addr_target: %s' % \
                  (case, ipv6_int, ipv6_addr_result, ipv6_addr_target)


if __name__ == '__main__':
    test_convert_int_to_ipv6()