import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class ipv6 {
private static final Character[] IPV6_CHARACTERS = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
private static final Set<Character> IPV6_CHARACTER_SET = new HashSet<>();
private static final BigInteger MAXIMUM_VALUE_OF_IPV6_SEGMENT;
private static final BigInteger MINIMUM_VALUE_OF_IPV6_SEGMENT;
static {
IPV6_CHARACTER_SET.addAll(Arrays.asList(IPV6_CHARACTERS));
MAXIMUM_VALUE_OF_IPV6_SEGMENT = new BigInteger("FFFF", 16);
MINIMUM_VALUE_OF_IPV6_SEGMENT = new BigInteger("0", 16);
}
/**
* @param string 一个疑似为 ipv6 地址的字符串
* @return FALSE or TRUE
*/
public static Boolean ipv6IsLegal(String string) {
// 如果特殊情况 直接返回结果
if (string == null || string.isBlank()) {
return Boolean.FALSE;
}
if (string.length() > 39 || string.length() < 2) {
return Boolean.FALSE;
}
// 全转换为小写字符
string = string.toLowerCase();
// 判断是否有不符合的字符 开始
for (Character character : IPV6_CHARACTER_SET) {
if (!IPV6_CHARACTER_SET.contains(character)) {
return Boolean.FALSE;
}
}
// 判断是否有不符合的字符 结束
// 如果有多个 ::
int index = string.indexOf("::");
int lastIndex = string.lastIndexOf("::");
if (index != lastIndex) {
return Boolean.FALSE;
}
if (string.equals("::")) {
return Boolean.TRUE;
}
// 如果存在 :: 并且只存在一次
if (index != -1) {
String before = string.substring(0, index);
String after = string.substring(index + 2);
int count = 0;
for (char c : before.toCharArray()) {
if (c == ':') {
count++;
}
}
for (char c : after.toCharArray()) {
if (c == ':') {
count++;
}
}
string = before + ":0".repeat(Math.max(0, 6 - count)) +
":" +
after;
}
String[] strings = string.split(":");
if (strings.length != 8) {
return Boolean.FALSE;
}
for (String str : strings) {
BigInteger bigInteger = new BigInteger(str, 16);
if (bigInteger.compareTo(MAXIMUM_VALUE_OF_IPV6_SEGMENT) > 0 || bigInteger.compareTo(MINIMUM_VALUE_OF_IPV6_SEGMENT) < 0) {
return Boolean.FALSE;
}
}
return Boolean.TRUE;
}
/**
* 复制于
* <dependency>
* <groupId>org.apache.tomcat.embed</groupId>
* <artifactId>tomcat-embed-core</artifactId>
* <version>10.1.17</version>
* </dependency>
*
* @param ipv6Address ipv6Address
* @return 统一格式的 ipv6Address
*/
public static String canonize(String ipv6Address) {
int ipv6AddressLength = ipv6Address.length();
if (ipv6Address.contains(".")) {
int lastColonPos = ipv6Address.lastIndexOf(58);
int lastColonsPos = ipv6Address.lastIndexOf("::");
if (lastColonsPos >= 0 && lastColonPos == lastColonsPos + 1) {
ipv6AddressLength = lastColonPos + 1;
} else {
ipv6AddressLength = lastColonPos;
}
} else if (ipv6Address.contains("%")) {
ipv6AddressLength = ipv6Address.lastIndexOf(37);
}
StringBuilder result = new StringBuilder();
char[][] groups = new char[8][4];
int groupCounter = 0;
int charInGroupCounter = 0;
int zeroGroupIndex = -1;
int zeroGroupLength = 0;
int maxZeroGroupIndex = -1;
int maxZeroGroupLength = 0;
boolean isZero = true;
boolean groupStart = true;
StringBuilder expanded = new StringBuilder(ipv6Address);
int colonsPos = ipv6Address.indexOf("::");
int length = ipv6AddressLength;
int change = 0;
int charCounter;
int j;
if (colonsPos >= 0 && colonsPos < ipv6AddressLength - 1) {
charCounter = 0;
for (j = 0; j < ipv6AddressLength; ++j) {
if (ipv6Address.charAt(j) == ':') {
++charCounter;
}
}
if (colonsPos == 0) {
expanded.insert(0, "0");
++change;
}
for (j = 0; j < 8 - charCounter; ++j) {
expanded.insert(colonsPos + 1, "0:");
change += 2;
}
if (colonsPos == ipv6AddressLength - 2) {
expanded.setCharAt(colonsPos + change + 1, '0');
} else {
expanded.deleteCharAt(colonsPos + change + 1);
--change;
}
length = ipv6AddressLength + change;
}
for (charCounter = 0; charCounter < length; ++charCounter) {
char c = expanded.charAt(charCounter);
if (c >= 'A' && c <= 'F') {
c = (char) (c + 32);
}
if (c != ':') {
groups[groupCounter][charInGroupCounter] = c;
if (!groupStart || c != '0') {
++charInGroupCounter;
groupStart = false;
}
if (c != '0') {
isZero = false;
}
}
if (c == ':' || charCounter == length - 1) {
if (isZero) {
++zeroGroupLength;
if (zeroGroupIndex == -1) {
zeroGroupIndex = groupCounter;
}
}
if (!isZero || charCounter == length - 1) {
if (zeroGroupLength > maxZeroGroupLength) {
maxZeroGroupLength = zeroGroupLength;
maxZeroGroupIndex = zeroGroupIndex;
}
zeroGroupLength = 0;
zeroGroupIndex = -1;
}
++groupCounter;
charInGroupCounter = 0;
isZero = true;
groupStart = true;
}
}
charCounter = groupCounter;
for (groupCounter = 0; groupCounter < charCounter; ++groupCounter) {
if (maxZeroGroupLength > 1 && groupCounter >= maxZeroGroupIndex && groupCounter < maxZeroGroupIndex + maxZeroGroupLength) {
if (groupCounter == maxZeroGroupIndex) {
result.append("::");
}
} else {
for (j = 0; j < 4; ++j) {
if (groups[groupCounter][j] != 0) {
result.append(groups[groupCounter][j]);
}
}
if (groupCounter < charCounter - 1 && (groupCounter != maxZeroGroupIndex - 1 || maxZeroGroupLength <= 1)) {
result.append(':');
}
}
}
j = result.length();
if (result.charAt(j - 1) == ':' && ipv6AddressLength < ipv6Address.length() && ipv6Address.charAt(ipv6AddressLength) == ':') {
result.delete(j - 1, j);
}
for (int i = ipv6AddressLength; i < ipv6Address.length(); ++i) {
result.append(ipv6Address.charAt(i));
}
return result.toString();
}
}