-3

I am validating an array of IPv4 addresses using javascript regex.
I am getting unexpected result when I use the global flag.
I run the code using Node 10 & 13 and on chrome browser and they all gave the same result.

var ips = ['22.231.113.64', '22.231.113.164', '22.231.113.164']
const pv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?\d{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|[0-1]?\d{1,2})$/g
console.log(
  ips.map(x => pv4.test(x))
)  

the above code is giving me

[true, false, true]

Notice that the one ip that gave me false is exactly the same as the one behind it that gave me true (on index 1,2)

If I run it without the global flag, and I got what I expect

[true, true, true]
mplungjan
  • 169,008
  • 28
  • 173
  • 236
Ghassan Karwchan
  • 3,355
  • 7
  • 37
  • 65
  • 1
    If you have the global flag, the regex becomes stateful, so then the order of execution matters. – VLAZ Jan 28 '20 at 12:47

1 Answers1

0

Here is an explanation of a working IPV4 regex.

  • For testing a singular regex, you do not need the global flag e.g. ^...$.
  • For finding all matches, use word boundaries with a global flag e.g. \b...\bg.
/\b  <-- word boundry start or a caret (^)
  (?:
    (?:
      25[0-5]|          <-- 250-255 or
      2[0-4][0-9]|      <-- 200-249 or
      [01]?[0-9][0-9]?  <-- 0-199
    )
    \.
  ){3} <-- THREE groups with a literal dot at the end
  (?:
    25[0-5]|          <-- 250-255 or
    2[0-4][0-9]|      <-- 200-249 or
    [01]?[0-9][0-9]?  <-- 0-199
  )
\b/  <-- word boundry end or a dollar-sign ($)

Example

const pv4_test = /^(?:(?: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]?)$/
const pv4_matchAll = /\b(?:(?: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]?)\b/g

var ips = ['22.231.113.64', '22.231.113.164', '22.231.113.255']

console.log(ips.map(ip => pv4_test.test(ip)))
console.log(ips.join(' ').match(pv4_matchAll))
.as-console-wrapper { top: 0; max-height: 100% !important; }
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132