[SOLVED] RegEx detecting IPv6 Address

I’m trying to get the Xojo Regex to detect IPv6 addresses but just cannot get it to work. I have IPv4 working and the IPv6 pattern I’m trying works in other languages. Below is the code I’m trying. A solution would be very appreciated.

      Dim rg as New RegEx
      dim rgm as RegExMatch
      rg.SearchPattern = "/^(((?=.*(::))(?!.*\\3.+\\3))\\3?|([\\dA-F]{1,4}(\\3|:\\b|$)|\\2))(?4){5}((?4){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})\\z/i" // PCRE pattern
      // rg.SearchPattern = "/^(((?=.*(::))(?!.*\\3.+\\3))\\3?|([\\dA-F]{1,4}(\\3|:\\b|$)|\\2))(?4){5}((?4){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})\\z/ai" // Perl pattern
      rgm = rg.Search(txtPing1.Text)
      if rgm <> nil then MsgBox "ipv6"

David,

I wrote a quick demo for you to match IPv6 address. The regular expression matching is done via a function I wrote to return an Array of matched IPv6 Addresses.

https://www.dropbox.com/s/i5pfhg9qz4b9q8o/IPv6RegExTest.xojo_binary_project

HTH.

Private Function fMatchIPV6(inStringtoProcess as String) As String()
  Dim MatchIPv46_RegEx as RegEx
  Dim MatchIPv46_RegExMatch as RegExMatch
  Dim MatchIPv46_HitText as String
  Dim MatchIPv46_Array() As String
  Dim Counter as Integer
  
  MatchIPv46_RegEx = New RegEx
  MatchIPv46_RegEx.Options.Greedy = True
  MatchIPv46_RegEx.Options.CaseSensitive = False
  MatchIPv46_RegEx.Options.MatchEmpty = True
  MatchIPv46_RegEx.Options.DotMatchAll = True
  MatchIPv46_RegEx.Options.StringBeginIsLineBegin = True
  MatchIPv46_RegEx.Options.StringEndIsLineEnd = True
  MatchIPv46_RegEx.Options.TreatTargetAsOneLine = False
  MatchIPv46_RegEx.SearchPattern = "^(?>(?>([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}))$"
  
  MatchIPv46_RegExMatch = MatchIPv46_RegEx.Search(inStringtoProcess)
  
  // This will match any IPv6 address and then continue to look for matches
  While MatchIPv46_RegExMatch <> Nil
    MatchIPv46_HitText = MatchIPv46_RegExMatch.SubExpressionString(0)
    MatchIPv46_Array.Append MatchIPv46_HitText+EndOfLine
    MatchIPv46_RegExMatch = MatchIPv46_RegEx.Search
  Wend
  
  Return MatchIPv46_Array()
 
End Function

I updated the Dropbox project and here is the updated code. I noticed that I was missing some matches because I wasn’t taking the input string and converting it to an input array prior to matching.

Private Function fMatchIPV6(inStringtoProcess as String) As String()
  Dim MatchIPv46_RegEx as RegEx
  Dim MatchIPv46_RegExMatch as RegExMatch
  Dim MatchIPv46_HitText as String
  Dim InStringArray() as String
  Dim MatchIPv46_Array() As String
  Dim Counter as Integer
  
  InStringArray() = Split(inStringtoProcess,EndOfLine)
  
  MatchIPv46_RegEx = New RegEx
  MatchIPv46_RegEx.Options.Greedy = True
  MatchIPv46_RegEx.Options.CaseSensitive = False
  MatchIPv46_RegEx.Options.MatchEmpty = True
  MatchIPv46_RegEx.Options.DotMatchAll = True
  MatchIPv46_RegEx.Options.StringBeginIsLineBegin = True
  MatchIPv46_RegEx.Options.StringEndIsLineEnd = True
  MatchIPv46_RegEx.Options.TreatTargetAsOneLine = False
  MatchIPv46_RegEx.SearchPattern = "^(?>(?>([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}))$"
  
  for i as integer = 0 to UBound(InStringArray)
    MatchIPv46_RegExMatch = MatchIPv46_RegEx.Search(InStringArray(i))
    
    // This will match any IPv6 address and then continue to look for matches
    While MatchIPv46_RegExMatch <> Nil
      MatchIPv46_HitText = MatchIPv46_RegExMatch.SubExpressionString(0)
      MatchIPv46_Array.Append MatchIPv46_HitText+EndOfLine
      MatchIPv46_RegExMatch = MatchIPv46_RegEx.Search
    Wend
    
  Next i
  
  Return MatchIPv46_Array()

End Function

I haven’t looked at either, but the pattern in a Xojo RegEx object should not start with a delimiter like “/”. Anything in the SearchPattern will be matched.

The same goes for an ending delimiter and the options after it. Use RegEx.Options to set your options.

So your pattern works fine when I removed the delimiters:

"^(((?=.*(::))(?!.*\\3.+\\3))\\3?|([\\dA-F]{1,4}(\\3|:\\b|$)|\\2))(?4){5}((?4){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})\\z"

You can put mode switches in the pattern instead of using RegEx.Options if you prefer. For example, code[/code] means case-insensitive.

I appreciate the two solutions but neither detects all IPv6 possibilities. I tried a bunch of tests and a lot of them got matched but I’ll give two examples that didn’t get matched (but do in other languages).

::2222:3333:4444:5555:6666:123.123.123.123
::123.123.123.123

Here are some links of valid and invalid IPv6 addresses.

http://home.deds.nl/~aeron/regex/valid_ipv6.txt
http://home.deds.nl/~aeron/regex/invalid_ipv6.txt

Hm interesting as it is missing the short abbreviated addresses. Ill add that also.

This pattern appears to catch them.

^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}))|:)))(%.+)?\\s*$

Can you verify for me as I updated the demo.
https://www.dropbox.com/s/i5pfhg9qz4b9q8o/IPv6RegExTest.xojo_binary_project

Thanks!

Mike, I guess you did what I just did: Pasted both the valid and invalid addresses into RegExRX to make sure your pattern matched the former and not the latter. :slight_smile:

Yes, yes I did using RegExRx :slight_smile:

Sweet!~ Thanks :slight_smile: And now time to look into purchasing that RegExRX app. That seems quite handy, especially since RegEx isn’t my thing.

Very much appreciate both of your time and effort!

David that was the best $5 I have spent on software. Glad the pattern worked out.