Please read before marking as duplicate
I have not been able to create or find a RegEx that works for all IPv6 formats (my test cases are below). I am aware of this question that everyone points to: Regular expression that matches valid IPv6 addresses However, They all combine IPv6 with IPv4 and/or do not work with all my test cases.
Requirements:
Coldfusion
and a pattern that works in PL/SQL
.PL/SQL
the pattern for it must stay under 512 characters. And Oracle supports only a narrow part of RegExp language. So the ColdFusion
pattern could end up being different than the PL/SQL
pattern, that is fine, so long as they both work.Here is the latest pattern I'm trying out:
^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$
This comes close for ColdFusion
but not 100%. It doesn't work at all in PL/SQL
.
Test Results http://regex101.com/r/wI8cI0 The bold items are the ones the pattern doesn't work for in ColdFusion
:
::
is actually a valid format, thanks @Sander Steffann.)I got test cases 8-11 from: http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzai2%2Frzai2ipv6addrformat.htm And was told: Test 9 and 11 are for IPv6 address prefix, not an IPv6 address, so those should not be match.
End result, I need them to work in statements like this:
ColdFusion:
<cfset IndexOfOccurrence1=REFind("^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$",value[i])>
PL/SQL:
if ( REGEXP_LIKE(v,'^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$','i') ) then
With much help from @nhahtdh in this answer https://stackoverflow.com/a/21943960/3112803 I have found breaking it up to be the best solution. Below is an example of how to do it in PL/SQL
, but it could be done this way in other languages. I'll do the same in ColdFusion
. For PL/SQL
the pattern needed to stay under 512 characters so breaking it up works great and it is simple to understand. It passed all my test cases in the original question.
if (
/* IPv6 expanded */
REGEXP_LIKE(v, '\A[[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){7}\z')
/* IPv6 shorthand */
OR (NOT REGEXP_LIKE(v, '\A(.*?[[:xdigit:]](:|\z)){8}')
AND REGEXP_LIKE(v, '\A([[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){0,6})?::([[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){0,6})?\z'))
/* IPv6 dotted-quad notation, expanded */
OR REGEXP_LIKE(v, '\A[[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){5}:(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}\z')
/* IPv6 dotted-quad notation, shorthand */
OR (NOT REGEXP_LIKE(v, '\A(.*?[[:xdigit:]]:){6}')
AND REGEXP_LIKE(v, '\A([[:xdigit:]]{1,4}(:[[:xdigit:]]{1,4}){0,4})?::([[:xdigit:]]{1,4}:){0,5}(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}\z'))
) then