用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地址的主要内容,如果未能解决你的问题,请参考以下文章