Java (not limited to) regexp to validate ip addresses

February 19, 2012

Ok, nothing extraordinary today, just some things that are worth mentioning..
Last week I was working on adding some features to an existing java webapp, that we use to control acquisition processes on an embedded system. While I was doing it, emerged the need to execute ping requests using web interface. The web interface is built upon Ext js 3.2, and is composed mainly of tabbed panels containing grids and forms. Our ping interface is made of a simple form, containing a text field and a button. When button is pressed, I execute a http post containing IP address of the host that will be “pinged”.
I needed some server side validation of Ip address, and a instant refresh of my knowledge about regexps.
First of all, if you need to compose and test regexps, my suggestion is to take a look to rubular , it’s fast and easy to use. You can compile regular expressions and test them against strings on the fly. Very useful to my needs.
After a couple of minutes trying various combination, I found this:

  Ad{1,3}[.]d{1,3}[.]d{1,3}[.]d{1,3}z

This regexp matches against a string containing an ip address formatted string. How? I will try to explain what the expression do analyzing the meaning of each single piece:

  • A
    This metacharacter means “start of the string”, we need it to put a sort of starting point marker. The presence of this char in the expression avoid matching against a malformed ip address like for example x192.168.2.3.
  • d{1,3}
    First meta d matches against digit characters. But how many digit we expect to find in our Ip address? A minimum of one to a maximum of three. So we need to use the {MIN,MAX} matching operator. d{1,3} means that we want to match a number, built of a minimum of one to a maximum of three digits.
  • \[.\]
    All chars enclosed into square brackets will be matched. More clearly, suppose that you want to know if there are numbers into a string: The regexp [d] will match if there is some numbers (or only one) into. In our ip case, we need to match against a dot after a group of digit, so we use [.]
    At this point, we have a regexp that matches against pattern X. or XX. or XXX. , where the X are only numbers. We need just to repeat the same pattern 4 times, one for every octet of an ip address: Ad{1,3}[.]d{1,3}d{1,3}[.]d{1,3}
  • z
    The z meta means “end of the String”. After 4 octets, we don’t want anything else in our ip. So we have to include z to avoid matching against a malformed ip address such as 192.168.231.2x or 192.168.2.90x.
    At this point we have an expression that matches against a string formatted like an ip address, but what happens if my string is something like 999.999.999.99 ? I mean, string is formatted correctly but, of course, is NOT a valid ip. With our regexp, we check only the format of the String. We know that a valid ip address is composed from 4 octets, and each one could be a number in the interval 0-255 (Probably this statement is not completely true, but it’s ok for our purposes). We need to check that every octet is within the range 0-255. How we can do this? There are many ways, one is to get every octet from the string, put them into an array and execute on that all the checks that we need. We could extract our octects using regexp capture operator. Our regexp become:
 
      A(d{1,3})[.](d{1,3})[.](d{1,3})[.](d{1,3})z
    

See that round brackets? Every char of the string that matches on meta enclosed into them will be stored in memory for later recall. AFAIK, the way in which you could retrieve the groups from memory depends on the used programming language.
Following, two Java methods that summarize the content of this post. I hope that all this things and toughts will be useful for someone, comments are opened!

final Pattern IP_PATTERN = Pattern.compile("\A(\d{1,3})[.](\d{1,3})[.](\d{1,3})[.](\d{1,3})z");  
  private boolean ipAddressValidator(String iPaddress){    
    Matcher m = IP_PATTERN.matcher(iPaddress);
    boolean matches = m.matches();
    boolean validIp = false;
    int[] octects = extractIpOctets(iPaddress);
    for(int octet: octects){
        if (octet > 255){
            validIp = false;
            break;
        } else {
            validIp = true;
        }               
    }
    return matches && validIp;
  }
  private int[] extractIpOctets(String ip){
      int[] octects = new int[4];
      Matcher group = IP_PATTERN.matcher(ip);
      boolean matchFound = group.find();
      if (matchFound) {
          for (int i=1; i<=group.groupCount(); i++) {
              octects[i-1] = Integer.valueOf(group.group(i));
          }
      }
      return octects;
  }