用Java压缩成IPV6地址

Posted

技术标签:

【中文标题】用Java压缩成IPV6地址【英文标题】:IPV6 address into compressed form in Java 【发布时间】:2011-10-26 00:25:21 【问题描述】:

我使用Inet6Address.getByName("2001:db8:0:0:0:0:2:1").toString()方法压缩IPv6地址,输出为2001:db8:0:0:0:0:2:1,但我需要2001:db8::2:1。 , 基本上压缩输出应该基于RFC 5952 standard, 也就是

    Shorten as Much as Possible :例如,2001:db8:0:0:0:0:2:1 必须缩短为 2001:db8::2:1。同样,2001:db8::0:1 是不可接受的, 因为符号“::”可以用来产生一个 更短的表示 2001:db8::1。

    Handling One 16-Bit 0 Field:符号“::”不得仅用于缩短一个 16 位 0 字段。 例如,表示 2001:db8:0:1:1:1:1:1 是正确的,但是 2001:db8::1:1:1:1:1 不正确。

    Choice in Placement of "::" : = 如果在“::”的位置上有其他选择,则 最长的连续 16 位 0 字段必须缩短(即, 具有三个连续零字段的序列在 2001 年被缩短: 0:0:1:0:0:0:1)。当连续 16 位 0 字段的长度 相等(即 2001:db8:0:0:1:0:0:1),第一个零序列 位必须缩短。例如 2001:db8::1:0:0:1 是正确的 表示。

我还检查了 another post in Stack overflow,但没有指定条件(示例选择 :: 的位置)。

是否有任何 java 库来处理这个问题?谁能帮帮我?

提前致谢。

【问题讨论】:

【参考方案1】:

这个怎么样?

String resultString = subjectString.replaceAll("((?::0\\b)2,):?(?!\\S*\\b\\1:0\\b)(\\S*)", "::$2").replaceFirst("^0::","::");

没有Java双反斜杠地狱的解释:

(       # Match and capture in backreference 1:
 (?:    #  Match this group:
  :0    #  :0
  \b    #  word boundary
 )2,  # twice or more
)       # End of capturing group 1
:?      # Match a : if present (not at the end of the address)
(?!     # Now assert that we can't match the following here:
 \S*    #  Any non-space character sequence
 \b     #  word boundary
 \1     #  the previous match
 :0     #  followed by another :0
 \b     #  word boundary
)       # End of lookahead. This ensures that there is not a longer
        # sequence of ":0"s in this address.
(\S*)   # Capture the rest of the address in backreference 2.
        # This is necessary to jump over any sequences of ":0"s
        # that are of the same length as the first one.

输入:

2001:db8:0:0:0:0:2:1
2001:db8:0:1:1:1:1:1
2001:0:0:1:0:0:0:1
2001:db8:0:0:1:0:0:1
2001:db8:0:0:1:0:0:0

输出:

2001:db8::2:1
2001:db8:0:1:1:1:1:1
2001:0:0:1::1
2001:db8::1:0:0:1
2001:db8:0:0:1::

(我希望最后一个例子是正确的——或者如果地址以0结尾,还有其他规则吗?)

【讨论】:

这在组有前导零时不起作用。例如。 2001:0db8:0:0000:00:000:0002:0000 -> 2001:db8::2:0。在使用正则表达式压缩它之前,我可以通过消除这些前导零来轻松解决这个问题。但是有一种方法可以在一个正则表达式中做到这一点? 0:0:0:0:5:6:7:8 变为 0::5:6:7:8。我认为应该改为::5:6:7:8。所以在最后加上.replaceFirst("^0::","::")【参考方案2】:

我最近遇到了同样的问题,希望(非常轻微地)改进蒂姆的回答。

以下正则表达式有两个优点:

((?:(?:^|:)0+\\b)2,):?(?!\\S*\\b\\1:0+\\b)(\\S*)

首先,它结合了匹配多个零的更改。其次,它还能正确匹配地址开头最长的零链的地址(例如0:0:0:0:0:0:0:1)。

【讨论】:

虽然这个正则表达式处理像“0:0:0:0:0:0:0:0”这样的地址并且正确地将它缩短为“::”,它不再匹配最长的组零(即它错误地将“0:0:1:0:0:0:0:0”缩短为“::1:0:0:0:0:0”而不是“0:0:1:: "。 这会将0000:0000:0000:0000:0000:0000:0000:0001 压缩为::0001 而不是::1【参考方案3】:

java-ipv6 几乎就是你想要的。从 0.10 版开始,它不会检查是否用 :: 缩短零的最长运行 - 例如 0:0:1:: 缩短为 ::1:0:0:0:0:0。不过,对于处理 IPv6 地址来说,它是一个非常不错的库,而且这个问题应该是 fixed with version 0.11,因此该库是 RFC 5952 compliant。

【讨论】:

【参考方案4】:

在进行了一些测试后,我认为以下内容涵盖了所有不同的 IPv6 场景:

"((?:(?::0|0:0?)\\b)2,):?(?!\\S*\\b\\1:0\\b)(\\S*)" -> "::$2"

【讨论】:

【参考方案5】:

Guava 的 InetAddresses 类具有 toAddrString(),其格式符合 RFC 5952。

【讨论】:

【参考方案6】:

The open-source IPAddress Java library 可以像描述的那样做,它提供了多种为 IPv4 和/或 IPv6 生成字符串的方法,包括 IPv6 匹配 rfc 5952 的规范字符串。免责声明:我是该库的项目经理。

使用您列出的示例,示例代码是:

    IPAddress addr = new IPAddressString("2001:db8:0:0:0:0:2:1").getAddress();
    System.out.println(addr.toCanonicalString());
    // 2001:db8::2:1
    addr = new IPAddressString("2001:db8:0:1:1:1:1:1").getAddress();
    System.out.println(addr.toCanonicalString());
    // 2001:db8:0:1:1:1:1:1
    addr = new IPAddressString("2001:0:0:1:0:0:0:1").getAddress();
    System.out.println(addr.toCanonicalString());
    // 2001:0:0:1::1
    addr = new IPAddressString("2001:db8:0:0:1:0:0:1").getAddress();
    System.out.println(addr.toCanonicalString());
    //2001:db8::1:0:0:1

【讨论】:

【参考方案7】:

不太优雅,但这是我的建议(基于 chrixm 工作):

public static String shortIpv6Form(String fullIP) 
        fullIP = fullIP.replaceAll("^01,3", "");
        fullIP = fullIP.replaceAll("(:01,3)", ":");
        fullIP = fullIP.replaceAll("(04:)", "0:");
        //now we have full form without unnecessaires zeros
        //Ex:
        //0000:1200:0000:0000:0000:0000:0000:0000 -> 0:1200:0:0:0:0:0:0
        //0000:0000:0000:1200:0000:0000:0000:8351 -> 0:0:0:1200:0:0:0:8351
        //0000:125f:0000:94dd:e53f:0000:61a9:0000 -> 0:125f:0:94dd:e53f:0:61a9:0
        //0000:005f:0000:94dd:0000:cfe7:0000:8351 -> 0:5f:0:94dd:0:cfe7:0:8351


        //compress to short notation
        fullIP = fullIP.replaceAll("((?:(?:^|:)0+\\b)2,):?(?!\\S*\\b\\1:0+\\b)(\\S*)", "::$2");

        return fullIP;
    

    结果:

    7469:125f:8eb6:94dd:e53f:cfe7:61a9:8351 -> 7469:125f:8eb6:94dd:e53f:cfe7:61a9:8351 7469:125f:0000:0000:e53f:cfe7:0000:0000 -> 7469:125f::e53f:cfe7:0:0 7469:125f:0000:0000:000f:c000:0000:0000 -> 7469:125f::f:c000:0:0 7469:125f:0000:0000:000f:c000:0000:0000 -> 7469:125f::f:c000:0:0 7469:0000:0000:94dd:0000:0000:0000:8351 -> 7469:0:0:94dd::8351 0469:125f:8eb6:94dd:0000:cfe7:61a9:8351 -> 469:125f:8eb6:94dd:0:cfe7:61a9:8351 0069:125f:8eb6:94dd:0000:cfe7:61a9:8351 -> 69:125f:8eb6:94dd:0:cfe7:61a9:8351 0009:125f:8eb6:94dd:0000:cfe7:61a9:8351 -> 9:125f:8eb6:94dd:0:cfe7:61a9:8351 0000:0000:8eb6:94dd:e53f:0007:6009:8350 -> ::8eb6:94dd:e53f:7:6009:8350 0000:0000:8eb6:94dd:e53f:0007:6009:8300 -> ::8eb6:94dd:e53f:7:6009:8300 0000:0000:8eb6:94dd:e53f:0007:6009:8000 -> ::8eb6:94dd:e53f:7:6009:8000 7469:0000:0000:0000:e53f:0000:0000:8300 -> 7469::e53f:0:0:8300 7009:100f:8eb6:94dd:e000:cfe7:6009:8351 -> 7009:100f:8eb6:94dd:e000:cfe7:6009:8351 7469:100f:8006:900d:e53f:cfe7:61a9:8351 -> 7469:100f:8006:900d:e53f:cfe7:61a9:8351 7000:1200:8e00:94dd:e53f:cfe7:0000:0001 -> 7000:1200:8e00:94dd:e53f:cfe7:0:1 0000:0000:0000:0000:0000:0000:0000:0000 -> :: 0000:0000:0000:94dd:0000:0000:0000:0000 -> 0:0:0:94dd:: 0000:1200:0000:0000:0000:0000:0000:0000 -> 0:1200:: 0000:0000:0000:1200:0000:0000:0000:8351 -> ::1200:0:0:0:8351 0000:125f:0000:94dd:e53f:0000:61a9:0000 -> 0:125f:0:94dd:e53f:0:61a9:0 7469:0000:8eb6:0000:e53f:0000:61a9:0000 -> 7469:0:8eb6:0:e53f:0:61a9:0 0000:125f:0000:94dd:0000:cfe7:0000:8351 -> 0:125f:0:94dd:0:cfe7:0:8351 0000:025f:0000:94dd:0000:cfe7:0000:8351 -> 0:25f:0:94dd:0:cfe7:0:8351 0000:005f:0000:94dd:0000:cfe7:0000:8351 -> 0:5f:0:94dd:0:cfe7:0:8351 0000:000f:0000:94dd:0000:cfe7:0000:8351 -> 0:f:0:94dd:0:cfe7:0:8351 0000:0000:0000:0000:0000:0000:0000:0001 -> ::1

【讨论】:

以上是关于用Java压缩成IPV6地址的主要内容,如果未能解决你的问题,请参考以下文章

CCNA-8.IPv6

IPV6地址格式分析

IPv6

C语言编程对IPV6地址进行压缩算法用函数实现

IPv6基础知识

java如何压缩成gz包