Проверка строки IPv4 в Java - PullRequest
       122

Проверка строки IPv4 в Java

44 голосов
/ 03 января 2011

Сильфонный метод проверяет, является ли строка правильным IPv4-адресом, он возвращает true, если он допустимЛюбые улучшения в регулярных выражениях и элегантности будут очень благодарны:

public static boolean validIP(String ip) {
    if (ip == null || ip.isEmpty()) return false;
    ip = ip.trim();
    if ((ip.length() < 6) & (ip.length() > 15)) return false;

    try {
        Pattern pattern = Pattern.compile("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
        Matcher matcher = pattern.matcher(ip);
        return matcher.matches();
    } catch (PatternSyntaxException ex) {
        return false;
    }
}

Ответы [ 16 ]

52 голосов
/ 09 марта 2011

Вот более легкий для чтения, немного менее эффективный способ, которым вы могли бы сделать это.

public static boolean validIP (String ip) {
    try {
        if ( ip == null || ip.isEmpty() ) {
            return false;
        }

        String[] parts = ip.split( "\\." );
        if ( parts.length != 4 ) {
            return false;
        }

        for ( String s : parts ) {
            int i = Integer.parseInt( s );
            if ( (i < 0) || (i > 255) ) {
                return false;
            }
        }
        if ( ip.endsWith(".") ) {
            return false;
        }

        return true;
    } catch (NumberFormatException nfe) {
        return false;
    }
}
45 голосов
/ 03 января 2011

ОБНОВЛЕНИЕ: Commons-HttpClient и его преемник HttpComponents-HttpClient приняли эту функциональность.Вы можете использовать эту версию следующим образом: InetAddressUtils.isIPv4Address(Str).


Версия для разработки Apache Commons Validator имеет класс InetAddressValidator, который имеетisValidInet4Address(String) метод для проверки того, что данный String является действительным адресом IPv4.

Исходный код можно просмотреть из хранилища., так что это может дать некоторые идеи для улучшения, если вы чувствуете, что они есть.

Быстрый взгляд на предоставленный код показывает, что ваш метод компилирует Pattern при каждом вызове метода.Я бы переместил этот класс Pattern в поле static, чтобы избежать дорогостоящего процесса компиляции шаблонов при каждом вызове.

21 голосов
/ 31 января 2012

Если вы хотите использовать библиотеку с выпущенной версией, поддерживающей как IPv4, так и поддержку IPv6, вы можете использовать Guava

boolean isValid = InetAddresses.isInetAddress("1.2.3.4");
15 голосов
/ 25 июня 2015

Вот решение, которое использует потоки Java 8 для проверки того, что адрес состоит ровно из 4 чисел от 0 до 255 включительно, разделенных точками:

public class IpValidation {

    /**
     * Check that a string represents a decimal number
     * @param string The string to check
     * @return true if string consists of only numbers without leading zeroes, false otherwise
     */
    public static boolean isDecimal(String string) {
        if (string.startsWith("0")) {
            if (string.length() == 1) {
                 // "0"
                 return true;
            }
            // The string has a leading zero but is not "0"
            return false;
        }
        for(char c : string.toCharArray()) {
            if(c < '0' || c > '9') {
                return false;
            }
        }
        return true;
    }

    public static boolean isIp(String string) {
        String[] parts = string.split("\\.", -1);
        return parts.length == 4 // 4 parts
                && Arrays.stream(parts)
                .filter(IpValidation::isDecimal) // Only decimal numbers
                .map(Integer::parseInt)
                .filter(i -> i <= 255 && i >= 0) // Must be inside [0, 255]
                .count() == 4; // 4 numerical parts inside [0, 255]
    }
}
14 голосов
/ 03 января 2011

Если вы не возражаете против использования разрешения DNS на недопустимых IP-адресах, таких как www.example.com, вы можете использовать методы InetAddress для проверки:

public static final boolean checkIPv4(final String ip) {
    boolean isIPv4;
    try {
    final InetAddress inet = InetAddress.getByName(ip);
    isIPv4 = inet.getHostAddress().equals(ip)
            && inet instanceof Inet4Address;
    } catch (final UnknownHostException e) {
    isIPv4 = false;
    }
    return isIPv4;
}

Метод проверяет, является ли это экземпляром Inet4Address и является ли параметр ip-адресом, а не именем хоста. Если вы ожидаете много имен хостов в качестве параметров, имейте в виду, что эта реализация использует DNS, чтобы попытаться разрешить его. Это может быть проблемой производительности.

В противном случае вы можете иметь пик в boolean sun.net.util.IPAddressUtil.isIPv4LiteralAddress(String src) как анализируется строка для проверки IPv4.

7 голосов
/ 20 июня 2015

Найти пример регулярного выражения из this

package com.mkyong.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class IPAddressValidator{

    private Pattern pattern;
    private Matcher matcher;

    private static final String IPADDRESS_PATTERN = 
        "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
        "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
        "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
        "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";

    public IPAddressValidator(){
      pattern = Pattern.compile(IPADDRESS_PATTERN);
    }

   /**
    * Validate ip address with regular expression
    * @param ip ip address for validation
    * @return true valid ip address, false invalid ip address
    */
    public boolean validate(final String ip){         
      matcher = pattern.matcher(ip);
      return matcher.matches();             
    }
}
5 голосов
/ 28 июня 2015

Думаю, это решение довольно элегантно, хотя для его понимания требуется минута.

Основная идея - взять подстроку и затем проверить ее.
Обратите внимание, что я переключаю xи y, поскольку начало подстроки всегда будет концом последней плюс 1.

Это решение примерно в 20 раз быстрее, чем вариант регулярного выражения, и в 2 раза быстрее, чем разбиение.

public static boolean validIP(String ip) {
    if(ip == null || ip.length() < 7 || ip.length() > 15) return false;

    try {
        int x = 0;
        int y = ip.indexOf('.');

        if (y == -1 || ip.charAt(x) == '-' || Integer.parseInt(ip.substring(x, y)) > 255) return false;

        x = ip.indexOf('.', ++y);
        if (x == -1 || ip.charAt(y) == '-' || Integer.parseInt(ip.substring(y, x)) > 255) return false;

        y = ip.indexOf('.', ++x);
        return  !(y == -1 ||
                ip.charAt(x) == '-' ||
                Integer.parseInt(ip.substring(x, y)) > 255 ||
                ip.charAt(++y) == '-' ||
                Integer.parseInt(ip.substring(y, ip.length())) > 255 ||
                ip.charAt(ip.length()-1) == '.');

    } catch (NumberFormatException e) {
        return false;
    }
}

Если вы знаете, что у вас будет много неправильных IP-адресов, рассмотрите возможность добавления следующего кода ниже первого if.Это сделает код в 1,5 раза медленнее, но в случае ошибки улучшите его на 700x

    for (int i = 0; i < ip.length(); i++) {
        if (!Character.isDigit(ip.charAt(i)) && ip.charAt(i) != '.') return false;
    }
4 голосов
/ 30 августа 2015

Большинство ответов (за исключением ответа Михаэля Конецки) неверны: например, 10.8 является действительным IP4-адресом (сокращение от 10.0.0.8).

См. Текстовое представление IPадреса в спецификациях Java.

Как видно из ссылки, для проверки числового представления может быть от 1 до 4 частей, и в каждом случае применяются разные ограничения на части.

4 голосов
/ 17 апреля 2015

Если вы используете код в вопросе, вам нужно изменить строку:

if ((ip.length() < 6) & (ip.length() > 15)) return false;

до

if ((ip.length() <= 6) || (ip.length() > 15)) return false;
3 голосов
/ 30 июня 2015

Я думаю, что правильный способ - создать класс IPAddress и создать его экземпляр, передав ему строковое представление IP-адреса.

Таким образом, вы можете разделить различные этапы проверки на методы экземпляра.и получить некоторое разделение интересов .

Например, здесь это, как правило, свой собственный метод, вызовите его просто isEmpty:

return (ip == null || ip.isEmpty());

Также это должнобыть отдельным методом, вы могли бы назвать его hasProbableLength.

ip = ip.trim();
return ((ip.length() < 6) & (ip.length() > 15));

Здесь происходит много вещей.Я попытался бы разбить это и, возможно, попытаться полностью пропустить регулярное выражение.

try {
    Pattern pattern = Pattern.compile("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
    Matcher matcher = pattern.matcher(ip);
    return matcher.matches();
} catch (PatternSyntaxException ex) {
    return false;
}

Сначала я разбил бы строку на точки и увидел, что получаю ровно четыре группы.Вызовите этот метод divideIntoGroups

Я бы затем проверил каждую из групп на значение от 0 до 255. Вызовите этот метод validateGroups

Теперь, когда у вас есть это, если вы когда-либоВы хотите расширить этот класс, чтобы также определить, является ли IP localhost или широковещательный адрес, это довольно легко сделать.Это то, что разделение интересов дает вам.

Вы также можете точно сказать, какое из ваших правил проверки было нарушено при проверке строки IP-адреса.Что-то, что регулярное выражение не будет.

...