web-dev-qa-db-fra.com

Validation de la chaîne IPv4 en Java

La méthode ci-dessous valide si chaîne est correcte. L'adresse IPv4 renvoie true si elle est valide. Toute amélioration de l'expression rationnelle et de l'élégance serait très appréciée: 

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;
    }
}
43
Mat B.

Voici un moyen plus facile à lire, légèrement moins efficace.

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;
    }
}
50
rouble

UPDATE: Commons-HttpClient et son successeur HttpComponents-HttpClient ont adopté cette fonctionnalité. Vous pouvez utiliser cette version comme ceci: InetAddressUtils.isIPv4Address(Str).


La version de développement de Apache Commons Validator a une classe InetAddressValidator qui possède une méthode isValidInet4Address(String) afin de vérifier si une String donnée est une adresse IPv4 valide.

Le code source peut être visualisé à partir du référentiel, ce qui pourrait vous donner des idées d’améliorations, le cas échéant.

Un rapide coup d'œil sur le code fourni montre que votre méthode compile une variable Pattern à chaque appel de la méthode. Je déplacerais cette classe Pattern dans un champ static afin d'éviter le processus coûteux de compilation de modèles à chaque appel.

44
coobird

Si vous souhaitez utiliser une bibliothèque avec une version publiée prenant en charge les supports IPv4 et IPv6, vous pouvez utiliser Guava

boolean isValid = InetAddresses.isInetAddress("1.2.3.4");
20
Stefan L

Voici une solution qui utilise des flux Java 8 pour vérifier que l’adresse est composée de 4 chiffres compris entre 0 et 255 inclus, séparés par des points:

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]
    }
}
15
Raniz

Si cela ne vous dérange pas d'utiliser la résolution DNS sur des adresses IP invalides comme www.example.com, vous pouvez utiliser les méthodes InetAddress pour vérifier 

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;
}

La méthode vérifie s'il s'agit d'une instance d'Inet4Address et si le paramètre correspond à l'adresse IP et non au nom d'hôte. Si vous attendez beaucoup de noms d’hôte en tant que paramètres, sachez que cette implémentation utilise DNS pour tenter de le résoudre. Cela pourrait être un problème de performance. 

Sinon, vous pouvez avoir un pic dans boolean Sun.net.util.IPAddressUtil.isIPv4LiteralAddress(String src) comment la chaîne est analysée pour IPv4-check.

14
Michael Konietzka

Trouvez un exemple de regex dans 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();             
    }
}
7
bigspawn

Je pense que cette solution est assez élégante, même si cela prend une minute pour la comprendre.

L'idée de base est de prendre une sous-chaîne et de la valider.
Veuillez noter que je change x et y, car le début d'une sous-chaîne sera toujours la fin de la dernière plus 1. 

Cette solution est environ 20 fois plus rapide qu’une variante regex et deux fois plus rapide que le fractionnement.

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;
    }
}

Si vous savez que vous aurez beaucoup de mauvaises adresses IP, ajoutez le code suivant sous le premier if. Cela rendra le code 1,5x plus lent, mais en cas d'erreur, améliorez-le de 700x

    for (int i = 0; i < ip.length(); i++) {
        if (!Character.isDigit(ip.charAt(i)) && ip.charAt(i) != '.') return false;
    }
5
arcs

Si vous utilisez le code dans la question, vous voudrez changer la ligne:

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

à 

if ((ip.length() <= 6) || (ip.length() > 15)) return false;
4
jtbr

La plupart des réponses (à l'exception de celle de Michael Konietzka) sont erronées: 10.8, par exemple, est une adresse IP4 valide (un raccourci pour 10.0.0.8).

Voir Représentation textuelle des adresses IP dans les spécifications Java.

Comme on peut le voir dans la référence, pour vérifier une représentation numérique, il peut y avoir 1 à 4 parties, et dans chaque cas, différentes limitations s'appliquent aux parties.

3
Jonathan Rosenne

Essayez d’utiliser la regex suivante pour IPv4

String ip4Regex="^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})(\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[0-9]{1,2})){3}$";

j'espère que ça aide :)

3
bane19

Je pense que le bon moyen est de construire une classe IPAddress et de l'instancier en lui donnant une représentation sous forme de chaîne de l'adresse IP.

De cette façon, vous pouvez diviser les différentes étapes de validation en méthodes d'instance et obtenir une séparation séparation de préoccupations .

Par exemple, ceci est typiquement sa propre méthode, appelez simplement ceci isEmpty:

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

De plus, cela devrait être une méthode distincte, vous pouvez appeler celle-ci hasProbableLength.

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

Ici, il se passe beaucoup de choses. Je voudrais essayer de casser cela et peut-être essayer de sauter la regex complètement.

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;
}

Je voudrais d'abord diviser la chaîne en points et voir que je reçois exactement quatre groupes. Appelez cette méthode divideIntoGroups

Je validerais ensuite chacun des groupes pour une valeur comprise entre 0 et 255. Appelez cette méthode validateGroups

Maintenant que vous avez ceci, si vous souhaitez un jour étendre cette classe pour rechercher également si l'adresse IP est localhost ou s'il s'agit d'une adresse de diffusion, il est assez facile de le faire. C’est ce que vous donne la séparation des préoccupations .

Vous pouvez également savoir exactement laquelle de vos règles de validation a été rompue lors de la validation de la chaîne d'adresse IP. Quelque chose que regex ne sera pas.

3
firelynx

Le moyen le plus simple que j'ai trouvé de vérifier si ip est correctement dans ipv4 consiste à utiliser commons-validator-1.4.0.jar a class 

org.Apache.commons.validator.routines.InetAddressValidator

InetAddressValidator

Par exemple. 

InetAddressValidator inetValidator = InetAddressValidator.getInstance();
inetValidator.isValidInet4Address(yourIPAddress);

qui utilise cette regex simple: -

  "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$";
2
Shekhar Khairnar
boolean isValid = inetAddressValidator.isValid(hostName) || hostName.equalsIgnoreCase("localhost");

même réponse que coobird. Ajoutez simplement localhost à la déclaration. La plupart des environnements prennent "localhost" comme nom d'hôte valide. Ce n'est pas un format ipv4 mais il devrait être inclus pour que sa validité soit prise en compte.

1
rinjan

La bibliothèque Java IPAddress le fera. Le javadoc est disponible sur le lien. Disclaimer: Je suis le chef de projet.

Cette bibliothèque prend en charge les protocoles IPv4 et IPv6 de manière transparente. Par conséquent, la validation de l'un ou de l'autre fonctionne de la même manière que ci-dessous et prend également en charge les adresses IPC4 de longueur préfixe CIDR. Il supporte les formats plus inhabituels comme inet_aton (par exemple 10.8 a été mentionné dans une autre réponse ici)

Vérifiez si une adresse est valide:

    String str = "1.2.3.4";
    IPAddressString addrString = new IPAddressString(str);
    try {
         IPAddress addr = addrString.toAddress();
         ...
    } catch(AddressStringException e) {
        //e.getMessage provides validation issue
    }
1
Sean F
public static boolean ipv4Check(String ipAddress){

    try{
        if(ipAddress!=null && !ipAddress.isEmpty()){
            String [] ip = ipAddress.split("\\.");
            if(ip.length!=4)
                return false;

            for(int i=0;i<=ip.length-1;i++){
                int j=Integer.parseInt(ip[i]);
                if(j<0 || j>255){
                    return false;
                }
            }
            if ( ipAddress.endsWith(".") ) {
                return false;
            }
            if ( ipAddress.startsWith(".") ) {
                return false;
            }

        }
        return true;
    } catch (NumberFormatException ex) {
        return false;
    }       
}
1
user7839057

Je suggérerais d'utiliser ce qui est disponible sur la plate-forme/le cadre que vous développez.

Si rien n’est suffisant pour vous, vous voudrez peut-être simplement ajouter une expression rationnelle compilée à une classe d’aide. Par exemple, ici comment le framework Android le fait:

public static final Pattern IP_ADDRESS
    = Pattern.compile(
        "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
        + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
        + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
        + "|[1-9][0-9]|[0-9]))");
1
Juan Andrés Diana