B.Fiel
B.Fiel

Reputation: 13

Multiple ip addresses in single string

I have that kind of datas :

172.12.1.3;185.16.6.13;...

And sometimes the submask so it could be :

172.12.1.3;185.16.6.13/32;172.12.1.4;...

So I wanted to use regex (in js) to be sure each ip address is correct using ";" as separator.

It should not be too difficult, but even with a few research i've just manage to do something like this :

/^(((^|\.?)(1[0-9]{2}|[1-9][0-9]|[0-9]|2[0-4][0-9]|25[0-5])){4}(\;|$))*$/

Btw I know that I should, but I'm not really into regex...

Can someone give me a hand please ?

edit :

So i've tried something like this :

var poolIp = v.split(";");

var ipAddress = /^(((^|\.?)(1[0-9]{2}|[1-9][0-9]|[0-9]|2[0-4][0-9]|25[0-5])){4}(\;|$))*$/;
var ret = true;
for (var i = 0; i < poolIp.length; i++) {
    var matches = ipAddress.exec(poolIp[i]);
    if (!matches) {
        ret = false;
    }
}
return ret;

And it's way better, but ip address with submask is not valid and ip with 3 digits are valid.

Upvotes: 1

Views: 897

Answers (2)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626754

You may use the following function to validate such strings of IP addresses. Note that the port number validation can be enhanced, I just check if the value is numeric.

function checkIsIPV4s(entry) {
  var ips = entry.split(';');       // Split into separate IPs
  for (var ip of ips) {
    var blocks = ip.split(/[.\/]/); // Split with dot and slash
    if(blocks.length === 5) {       // If there are 5 blocks,
      var last = blocks.pop();      //   remove the last one 
      if (!/^\d+$/.test(last)) {    //   and check if it is numeric
        return false;               //   if not - FALSE
      }
    }
    if(blocks.length === 4) {       // If block number is 4
      var res = blocks.every(function(block) { // check each part
        return parseInt(block,10) >=0 && parseInt(block,10) <= 255;
      });
      if (!res) {return false; }    // If any part is not in 0..255 - FALSE
    } else {  
      return false;                 // If block number is not 4 - FALSE
    }
  }
  return true;
}
var str = "172.12.1.3;185.16.6.13/32;172.12.1.4;255.255.255.255";
console.log(checkIsIPV4s(str));
str2 = "172.12.1.34444;185.16.6.13/32";
console.log(checkIsIPV4s(str2));

However, there is a way to use a huge and unreadable regex, too. Adding this just to show that it is possible to do it with a regex:

/^(?:(?:\d{1,2}|1\d{2}|2(?:[0-4]\d|5[0-5]))\.){3}(?:\d{1,2}|1\d{2}|2(?:[0-4]\d|5[0-5]))(?:\/\d+)?(?:;(?:(?:\d{1,2}|1\d{2}|2(?:[0-4]\d|5[0-5]))\.){3}(?:\d{1,2}|1\d{2}|2(?:[0-4]\d|5[0-5]))(?:\/\d+)?)*$/

See the regex demo

The pattern matches:

  • ^ - start of string
  • (?:(?:\d{1,2}|1\d{2}|2(?:[0-4]\d|5[0-5]))\.){3}(?:\d{1,2}|1\d{2}|2(?:[0-4]\d|5[0-5]))(?:\/\d+)? - a single IP pattern (all up to (?:\/\d+)?) with an optional port number ((?:\/\d+)?)
  • (?: - the non-capturing group start
    • ; - the separator
    • (?:(?:\d{1,2}|1\d{2}|2(?:[0-4]\d|5[0-5]))\.){3}(?:\d{1,2}|1\d{2}|2(?:[0-4]\d|5[0-5]))(?:\/\d+)? - the single IP pattern, same as above
  • )* - 0 or more occurrences of the non-capturing group sequences
  • $ - end of string.

Upvotes: 2

fredrik
fredrik

Reputation: 17617

This should do it:

var re = /^(;?[1-9][\d]{1,2}(\.[\d]{1,3}){3}(\/[\d]{1,3})?)+$/
re.test('172.12.1.3;185.16.6.13/32;172.12.1.4') // true
re.test('172.12.1.3;185.16.6.13/32;172.12.1') // false
re.test('072.12.1.3;185.16.6.13/32;172.12.1.4') // false

Or splitting them up:

var re = /^[1-9][\d]{1,2}(\.[\d]{1,3}){3}(\/[\d]{1,3})?$/
var ip1 = '172.12.1.3;185.16.6.13/32;172.12.1.4'.split(';');
var ip2 = '172.12.1.3;185.16.6.13/32;172.12.1'.split(';');
var ip3 = '072.12.1.3;185.16.6.13/32;172.12.1.4'.split(';');
ip1.every((ip) => re.test(ip));
ip2.every((ip) => re.test(ip));
ip3.every((ip) => re.test(ip));

You can use http://regexr.com/ to test your regexp, and read about Array.every here.

Upvotes: 1

Related Questions