59

Bellow method is validating if string is correct IPv4 address it returns true if it is valid. Any improvements in regex and elegance would be very appreciated:

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;
    }
}
MatBanik
  • 26,356
  • 39
  • 116
  • 178
  • There are different representations possible. You are looking for dot-decimal notation: See http://en.wikipedia.org/wiki/IPv4#Address_representations – Michael Konietzka Jan 03 '11 at 10:47
  • an ip.length() of 7 is valid, for example 0.0.0.0 is 7 characters, your method will return false. – rouble Mar 08 '11 at 23:17
  • 2
    I am wondering why this is still no part of some third party library. I mean avoiding third party libraries is good but figuring the regex for that is highly error-prone which is in my opinion worse than using a third party API. – Arthur Eirich Jun 23 '15 at 20:39
  • 1
    The regex is fine, you just have to replace `[0-9]` for `\d`and take the Pattern compilation outside the method so you don't have to compile it everytime. – Javier Diaz Jun 28 '15 at 12:13

17 Answers17

65

Here is an easier-to-read, slightly less efficient, way you could go about it.

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;
    }
}
rouble
  • 16,364
  • 16
  • 107
  • 102
  • 4
    I prefer this approach more. – theGrayFox Jun 12 '14 at 04:27
  • 1
    If you do `ip.split("\\.", -1)` you can delete the `if (ip.endsWith(".")) ...` bit – samthebest Aug 07 '14 at 19:00
  • You might want to check for leading zeroes in each part, see http://superuser.com/questions/857603/are-ip-addresses-with-and-without-leading-zeroes-the-same – Vinicius Braz Pinto Jun 30 '15 at 05:35
  • 1
    "192.168.1" is a valid IP address. I think your method has a flaw. – PEdroArthur Jun 30 '15 at 14:00
  • 1
    @PEdroArthur Four dotted numbers is a pretty standard representation of an IPV4 address. The dotted octet format was never really specified in an RFC. The first mention is in the MTP RFC (circa 1981) says, "four small decimal integers separated by dots and enclosed by brackets, e.g., "[123.255.37.321]", which indicates a 32 bit ARPA Internet Address in four eight bit fields." Do you have any source that indicates that "192.168.1" is valid? – rouble Aug 12 '15 at 14:36
  • 2
    @rouble I don't know. However, all network stacks that I use do accept address like 192.168.1 (192.168.0.1) and 10.1 (10.0.0.1). – PEdroArthur Aug 19 '15 at 20:11
  • https://superuser.com/questions/486788/why-does-pinging-192-168-072-only-2-dots-return-a-response-from-192-168-0-58 – user842313 Jul 26 '17 at 07:20
  • Will the above solution work for IPv4Address and IPv6Address as well ,Can you add testing use cases if possible? – deepakl.2000 May 29 '21 at 17:09
  • check this "01.233.161.131" – b m gevariya Jul 07 '21 at 11:35
  • @rouble,Will the above solution work for IPv4Address and IPv6Address as well ,Can you modify the code for IPV4ADDRESS and IPV6ADDRESS ? – deepakl.2000 Oct 28 '21 at 10:50
54

UPDATE: Commons-HttpClient and its successor HttpComponents-HttpClient have adopted this functionality. You can utilize this version of it like so: InetAddressUtils.isIPv4Address(Str).


The development version of Apache Commons Validator has a InetAddressValidator class which has a isValidInet4Address(String) method to perform a check to see that an given String is a valid IPv4 address.

The source code can be viewed from the repository, so that might provide some ideas for improvements, if you feel there are any.

A quick glance at the provided code shows that your method is compiling a Pattern on each invocation of the method. I would move that Pattern class out to a static field to avoid the costly pattern compilation process on each call.

forresthopkinsa
  • 1,339
  • 1
  • 24
  • 29
coobird
  • 159,216
  • 35
  • 211
  • 226
21

If you want to use a library with a released version suppporting both IPv4 and IPv6 support, you can use Guava

boolean isValid = InetAddresses.isInetAddress("1.2.3.4");
MatBanik
  • 26,356
  • 39
  • 116
  • 178
Stefan L
  • 1,529
  • 13
  • 20
17

Here's a solution that uses Java 8 streams to check that the address consists of exactly 4 numbers between 0 and 255 inclusive, separated by dots:

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) {
        // Check whether string has a leading zero but is not "0"
        if (string.startsWith("0")) {
            return string.length() == 1;
        }
        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]
    }
}
Jonathan Rosenne
  • 2,159
  • 17
  • 27
Raniz
  • 10,882
  • 1
  • 32
  • 64
  • I don't think this is correct in all scenarios. This method returns true for 172.013.1.2 which is an invalid IP address string. It should be 172.13.1.2 instead. The 'isNumeric' method can be modified to correct this. – radiantRazor Aug 13 '16 at 18:53
  • 172.013.1.2 *is* a valid IP address. As is 172.013.001.002. Leading zeroes are usually avoided though because they may imply that the number is in octal instead of decimal. – Raniz Aug 15 '16 at 06:46
  • http://www.ipaddressguide.com/ip and http://sqa.fyicenter.com/Online_Test_Tools/IP_Address_Format_Validator.php and https://commons.apache.org/proper/commons-validator/apidocs/src-html/org/apache/commons/validator/routines/InetAddressValidator.html#line.86 Say it is invalid http://formvalidation.io/validators/ip/ and http://www.csgnetwork.com/directipverify.html?IPvalue=172.013.001.002 say it is valid – radiantRazor Aug 16 '16 at 11:50
  • `ping 192.168.001.001` works from terminal in Linux, that's good enough for me :) – Raniz Aug 16 '16 at 12:27
  • 4
    `ping 192.168.1.09` ping: cannot resolve 192.168.1.09: Unknown host Summary: IP segment starting with 0 indicates that the segment is in octal, so we also need to validate that the remaining digits do not contain 7,8 (I admit i didn't know this before: thats y i gave the examples as 172.013.1.2 The correct test case to test is 172.13.1.008 - which fails) Long story short: The above validation is not correct and can lead to false positives – radiantRazor Aug 17 '16 at 14:15
  • 2
    "works in one case, that's good enough for me." That's plenty of reason for a downvote. Sad that this answer received a bounty. The reason that one case worked is that the numbers starting with `0` (`001` in this case) mean the same in octal as in decimal. That's only true if there is only one non-zero digit, with no zeroes after it, and that digit isn't 8 or 9. Yikes. – LarsH Jul 11 '17 at 16:45
  • Leading zeroes _are_ allowed in IP addresses though, but since the interpretation of them is a bit ambiguous I'll change the answer to not allow leading zeroes. – Raniz Jul 14 '17 at 10:41
  • Will the above solution work for IPv4Address and IPv6Address as well ,Can you add testing use cases if possible? – deepakl.2000 May 29 '21 at 17:12
  • It will definitely _not_ work for IPv6 addresses since they use a completely different format – Raniz May 29 '21 at 19:23
  • @Raniz ,Can you please add the java code for IPv6 addresses .Can you please add the java main method to check for IPv4Address and IPv6Address testing scenarios? – deepakl.2000 May 30 '21 at 06:33
  • I suggest you search SO for a similar question or ask one yourself if you can't find one since that is different problem – Raniz May 31 '21 at 07:33
17

If you don't mind using dns resolution on invalid ip-addresses like www.example.com, you can use the InetAddress methods to check:

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

The method checks if it is an instance of Inet4Address and if the parameter was the ip-address and not the hostname. If you expect a lot of hostnames as parameters, beware that this implementation uses DNS to try to resolve it. This might be a performance concern.

Otherwise you can have a peak into boolean sun.net.util.IPAddressUtil.isIPv4LiteralAddress(String src) how the String is parsed there for IPv4-check.

Michael Konietzka
  • 5,419
  • 2
  • 28
  • 29
  • 2
    FWIW, here's what i usually do: first use a simple regexp to check that the parameter consists of 4 dot-separated numbers (i don't try to check if the numbers are within range, etc, just the general format). If this first check passes, then i use InetAddress as in this answer to finish the validation. – theglauber Feb 01 '12 at 20:58
7

Find regex example from 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();             
    }
}
bigspawn
  • 1,727
  • 3
  • 16
  • 16
  • 1
    I don't think this is correct in all scenarios. This method returns true for 172.013.1.2 which is an invalid IP address string. It should be 172.13.1.2 instead. – radiantRazor Aug 13 '16 at 19:07
  • @radiantRazor 172.013.1.2 is a valid address, albeit probably misleading, since 013 is often interpreted a octal, i.e. 11. See [Dot-decimal notation] (https://en.wikipedia.org/wiki/Dot-decimal_notation). – Jonathan Rosenne Apr 06 '19 at 13:29
5

In think this solution is quite elegant, although it takes a minute to understand it.

The basic idea is to take a sub-string and than validate it.
Please note that I switch x and y, since the start of a sub-string will always be the end of the last one plus 1.

This solution is about 20x faster than a regex variant and 2x faster than splitting.

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

If you know that you'll have a lot wrong IPs consider adding the following code below the first if. This will make the code 1.5x slower but in case of an error improve it by 700x

    for (int i = 0; i < ip.length(); i++) {
        if (!Character.isDigit(ip.charAt(i)) && ip.charAt(i) != '.') return false;
    }
arc
  • 4,553
  • 5
  • 34
  • 43
  • Will the above solution work for IPv4Address and IPv6Address as well ,Can you add testing use cases if possible using main() method – deepakl.2000 May 29 '21 at 17:20
  • It is the fastest function that I have tested for IPv4 but can we extend it for IPv6 also? – banjara Aug 08 '21 at 14:08
4

If you use the code in the question, you'll want to change the line:

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

to

if ((ip.length() <= 6) || (ip.length() > 15)) return false;
jtbr
  • 1,149
  • 13
  • 13
4

Try using the following regrex for 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}$";

hope it helps :)

bane19
  • 384
  • 2
  • 15
4

Most of the answers (except that of Michael Konietzka) are wrong: 10.8, for instance, is a valid IP4 address (a shorthand for 10.0.0.8).

SeeTextual representation of IP addresses in the Java specifications.

As may be seen in the reference, to check a numeric representation, there may be 1 to 4 parts, and in each case different limitations on the parts apply.

Jonathan Rosenne
  • 2,159
  • 17
  • 27
3

I think the proper way is to build an IPAddress class and instanciate it by giving it a string representation of the the ip address.

This way you can split out the different validation steps into instance methods and get some separation of concern going.

For instance, this here is typically it's own method, call this simply isEmpty:

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

Also this should be a separate method, you could call this one hasProbableLength.

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

Here there are lots of things going on. I would try to break this up and perhaps try to skip the regex completely.

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

I would first split the string on dots and see that I get exactly four groups. Call this method divideIntoGroups

I would then validate each of the groups for being a value between 0 and 255. Call this method validateGroups

Now that you have this, if you ever want to extend this class to also look for if the IP is localhost or if it is a broadcast address, it is pretty easy to do this. This is what separation of concerns gives you.

You can also tell exactly which one of your validation rules was broken in the validation of the IP address string. Something that regex will not.

firelynx
  • 30,616
  • 9
  • 91
  • 101
3

The IPAddress Java library will do it. The javadoc is available at the link. Disclaimer: I am the project manager.

This library supports IPv4 and IPv6 transparently, so validating either works the same below, and it also supports CIDR prefix-length IPC4 addresses as well. It supports the more unusual formats like inet_aton (for example 10.8 was mentioned in another answer here)

Verify if an address is valid:

    String str = "1.2.3.4";
    IPAddressString addrString = new IPAddressString(str);
    try {
         IPAddress addr = addrString.toAddress();
         ...
    } catch(AddressStringException e) {
        //e.getMessage provides validation issue
    }
Sean F
  • 4,344
  • 16
  • 30
2

Most simple way I found to check given ip is correctly in ipv4 is to use commons-validator-1.4.0.jar has class:--

org.apache.commons.validator.routines.InetAddressValidator

InetAddressValidator

E.g.

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

which uses this simple regex :--

  "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$";
Shekhar Khairnar
  • 2,643
  • 3
  • 26
  • 44
2

It will be useful for you,


boolean isIPv4Address(String inputString) {
    String[] splitString = inputString.split("[.]");
    if (splitString.length > 4) {
        return false;
    }
    for (String string : splitString) {
        if (string.isEmpty()) {
            return false;
        }
        if (!string.matches("[0-9]{1,3}")) {
            return false;
        }
        int number = Integer.parseInt(string);
        if (!(number >= 0 && number <= 255)) {
            return false;
        }
    }
    return true;
}

1

I would suggest using what's available on the platform/framework you are developing.

If there's nothing you consider good enough, then you might just want to add a compiled regex to a helper class. For instance, here's how the Android framework does it:

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]))");
Juan Andrés Diana
  • 2,215
  • 3
  • 25
  • 36
1
boolean isValid = inetAddressValidator.isValid(hostName) || hostName.equalsIgnoreCase("localhost");

same answer as coobird. Just add localhost to the statement. Most of the environments takes 'localhost' as a valid host name. It is not a ipv4 format but it should be included to consider validity.

rinjan
  • 550
  • 5
  • 19
1
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;
    }       
}
HDJEMAI
  • 9,436
  • 46
  • 67
  • 93
Amit Kumar
  • 19
  • 2
  • Will the above solution work for IPv4Address and IPv6Address as well ,Can you add testing use cases if possible? – deepakl.2000 May 29 '21 at 17:13
  • This is to check ipv4 not ipv6 as both have different structure – Amit Kumar Oct 01 '21 at 10:55
  • Can you add the java solution for IPv6Address as well Can you add testing use cases for IPv4Address and IPv6Address from public static void main method in java @Amit Kumar – deepakl.2000 Oct 28 '21 at 10:46