IPV6地址在Java中压缩成形式

时间:2011-08-12 17:26:57

标签: java regex ipv6 regex-negation

我使用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,即

1)Shorten as Much as Possible:例如,2001:db8:0:0:0:0:2:1必须缩短为
                                  2001:db8 :: 2:1.Likewise,2001:db8 :: 0:1是不可接受的,                                   因为符号“::”本来可以用来产生一个                                   较短的表示形式2001:db8 :: 1。

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

3)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库来处理这个问题?有人可以帮帮我吗?

提前致谢。

7 个答案:

答案 0 :(得分:19)

这个怎么样?

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

没有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结尾,还是有其他规则吗?)

答案 1 :(得分:9)

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

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

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

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

答案 2 :(得分:2)

java-ipv6几乎就是你想要的。从版本0.10开始,它不检查用:: - 例如0:0:1 ::缩短为:: 1:0:0:0:0:0时缩短的最长零。但是,它是一个非常不错的处理IPv6地址的库,这个问题应该是fixed with version 0.11,这样库就是RFC 5952 compliant

答案 3 :(得分:1)

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

答案 4 :(得分:0)

执行一些测试后,我认为以下内容捕获了所有不同的IPv6场景:

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

public static String shortIpv6Form(String fullIP) {
        fullIP = fullIP.replaceAll("^0{1,3}", "");
        fullIP = fullIP.replaceAll("(:0{1,3})", ":");
        fullIP = fullIP.replaceAll("(0{4}:)", "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;
    }
  1. 结果:

    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