@MichaelR - Your regexes have some problems and fail to match some valid addresses. First off, the IPv4 regex:
MichaelR wrote:Code: Select all
// IPv4
'/^(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}$/i'
This regex has one error and a couple possible simplifications:
- It fails to match valid IP octets having leading zeroes e.g. 192.168.001.020
- Each set of digits is surrounded by an unnecessary non-capturing group. e.g. '(?:25[0-5])|(?:2[0-4][0-9])' can be written more simply as: '25[0-5]|2[0-4][0-9]'.
- The 'i' ignorecase modifier is unnecessary as there are no alpha chars.
Concerning the IPv6 regexes. First off lets look at what they should be matching. Here is a list of test IPv6 example addresses having valid syntax:
Code: Select all
ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
::ffff:ffff:ffff:ffff:ffff:ffff:ffff
::ffff:ffff:ffff:ffff:ffff:ffff
ffff::ffff:ffff:ffff:ffff:ffff:ffff
::ffff:ffff:ffff:ffff:ffff
ffff::ffff:ffff:ffff:ffff:ffff
ffff:ffff::ffff:ffff:ffff:ffff:ffff
::ffff:ffff:ffff:ffff
ffff::ffff:ffff:ffff:ffff
ffff:ffff::ffff:ffff:ffff:ffff
ffff:ffff:ffff::ffff:ffff:ffff:ffff
::ffff:ffff:ffff
ffff::ffff:ffff:ffff
ffff:ffff::ffff:ffff:ffff
ffff:ffff:ffff::ffff:ffff:ffff
ffff:ffff:ffff:ffff::ffff:ffff:ffff
::ffff:ffff
ffff::ffff:ffff
ffff:ffff::ffff:ffff
ffff:ffff:ffff::ffff:ffff
ffff:ffff:ffff:ffff::ffff:ffff
ffff:ffff:ffff:ffff:ffff::ffff:ffff
::ffff
ffff::ffff
ffff:ffff::ffff
ffff:ffff:ffff::ffff
ffff:ffff:ffff:ffff::ffff
ffff:ffff:ffff:ffff:ffff::ffff
ffff:ffff:ffff:ffff:ffff:ffff::ffff
::
ffff::
ffff:ffff::
ffff:ffff:ffff::
ffff:ffff:ffff:ffff::
ffff:ffff:ffff:ffff:ffff::
ffff:ffff:ffff:ffff:ffff:ffff::
ffff:ffff:ffff:ffff:ffff:ffff:ffff::
ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255
::ffff:ffff:ffff:ffff:ffff:255.255.255.255
::ffff:ffff:ffff:ffff:255.255.255.255
ffff::ffff:ffff:ffff:ffff:255.255.255.255
::ffff:ffff:ffff:255.255.255.255
ffff::ffff:ffff:ffff:255.255.255.255
ffff:ffff::ffff:ffff:ffff:255.255.255.255
::ffff:ffff:255.255.255.255
ffff::ffff:ffff:255.255.255.255
ffff:ffff::ffff:ffff:255.255.255.255
ffff:ffff:ffff::ffff:ffff:255.255.255.255
::ffff:255.255.255.255
ffff::ffff:255.255.255.255
ffff:ffff::ffff:255.255.255.255
ffff:ffff:ffff::ffff:255.255.255.255
ffff:ffff:ffff:ffff::ffff:255.255.255.255
::255.255.255.255
ffff::255.255.255.255
ffff:ffff::255.255.255.255
ffff:ffff:ffff::255.255.255.255
ffff:ffff:ffff:ffff::255.255.255.255
ffff:ffff:ffff:ffff:ffff::255.255.255.255
A correct IPv6 regex (such as the one I provided in my previous post) should match every one of these IPv6 example addresses. Note that the first section of addresses are purely colon separated 16-bit numbers, while the second section of addresses consist of an IPv4 (dot separated 8-bit values) syntax for the least significant 32-bits. In other words, the least significant 32-bits of an IPv6 address can be represented as either two 16-bit values (each having up to four hexadecimal digits separated by a colon), or as four 8-bit values (each having up to three decimal digits (less than 256) separated by a dot). An optional double colon acts as a wildcard for one or more zeroed 16-bit values.
Here is your first IPv6 regex which attempts to match the first category:
MichaelR wrote:Code: Select all
// IPv6
'/^(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9](?::|$)){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?))$/i'
This regex fails to match the following:
Code: Select all
::ffff:ffff:ffff:ffff:ffff:ffff:ffff
ffff::ffff:ffff:ffff:ffff:ffff:ffff
ffff:ffff::ffff:ffff:ffff:ffff:ffff
ffff:ffff:ffff::ffff:ffff:ffff:ffff
ffff:ffff:ffff:ffff::ffff:ffff:ffff
ffff:ffff:ffff:ffff:ffff::ffff:ffff
ffff:ffff:ffff:ffff:ffff:ffff::ffff
ffff:ffff:ffff:ffff:ffff:ffff:ffff::
Here is your second IPv6 regex which attempts to match the second category:
MichaelR wrote:Code: Select all
// IPv4-mapped IPv6
'/^(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?))(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}$/i'
This regex fails to match the following:
Code: Select all
::ffff:ffff:ffff:ffff:ffff:255.255.255.255
ffff::ffff:ffff:ffff:ffff:255.255.255.255
ffff:ffff::ffff:ffff:ffff:255.255.255.255
ffff:ffff:ffff::ffff:ffff:255.255.255.255
ffff:ffff:ffff:ffff::ffff:255.255.255.255
ffff:ffff:ffff:ffff:ffff::255.255.255.255
Lastly, here is your final regex which should match all IPv6 addresses:
MichaelR wrote:Code: Select all
// IPv4, IPv6, or IPv4-mapped IPv6
'/^(?:(?:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9](?::|$)){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))$/i'
And as expected, this regex fails to match the following:
Code: Select all
::ffff:ffff:ffff:ffff:ffff:ffff:ffff
ffff::ffff:ffff:ffff:ffff:ffff:ffff
ffff:ffff::ffff:ffff:ffff:ffff:ffff
ffff:ffff:ffff::ffff:ffff:ffff:ffff
ffff:ffff:ffff:ffff::ffff:ffff:ffff
ffff:ffff:ffff:ffff:ffff::ffff:ffff
ffff:ffff:ffff:ffff:ffff:ffff::ffff
ffff:ffff:ffff:ffff:ffff:ffff:ffff::
::ffff:ffff:ffff:ffff:ffff:255.255.255.255
ffff::ffff:ffff:ffff:ffff:255.255.255.255
ffff:ffff::ffff:ffff:ffff:255.255.255.255
ffff:ffff:ffff::ffff:ffff:255.255.255.255
ffff:ffff:ffff:ffff::ffff:255.255.255.255
ffff:ffff:ffff:ffff:ffff::255.255.255.255
I'm not sure where you got these IPv6 regex from but, simply put, they do not work correctly. Sorry to be the messenger here, but you really need to test your regexes before posting them!
For IP matching regexes
which actually work (for both IPv4 and IPv6), please refer to my previous posts. Here they are again in compressed format:
Code: Select all
// IPv4
$IPv4address = '/(?:(?: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]?)/';
// IPv6
$IPv6address = '/(?:(?:(?:[0-9A-Fa-f]{1,4}:){6}|::(?:[0-9A-Fa-f]{1,4}:){5}|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::)(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?: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]?))|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)/';
If anyone is curious where I came up with this IPv6 regex, I got it directly from the horse's mouth: i.e. from
RFC3986 - Uniform Resource Identifier (URI): Generic Syntax. I simply took the ABNF syntax for IPv6address from Appendix A and converted it into regex format. If you look at the commented version in my previous post, you can immediately see the resemblance.
Hope this helps
