检测IPV6地址是否合法的Java工具类

发布时间 2024-01-05 19:30:10作者: tothk
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();
    }

}

最后编辑时间:2024年1月5日19:24:02