Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

oracle - Regular Expression (RegEx) for IPv6 Separate from IPv4

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:

  1. I do not want it to also validate IPv4 values, I already have a separate validation function for IPv4.
  2. I need a pattern that works in Coldfusion and a pattern that works in PL/SQL.
  3. Because I'm using it in 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.
  4. End result doesn't have be one long RegEx, it can be split up.

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:

  1. match
  2. match
  3. match
  4. match
  5. match
  6. match (but @Michael Hampton says this should not match because it's not a valid IPv6 address, but others have told me it is valid, so I'm not sure about this test case.)
  7. match (:: is actually a valid format, thanks @Sander Steffann.)
  8. match
  9. no match
  10. match
  11. no match
  12. no match
  13. no match
  14. match
  15. match
  16. no match
  17. no match
  18. no match
  19. no match

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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...