So I need to match an ipv6 address which may or may not have a mask. Unfortunately I can't just use a library to parse the string.
The mask bit is easy enough, in this case:
(?:\/\d{1,3})?$/
The hard part is the different formats of an ipv6 address. It needs to match ::beef, beef::, beef::beef, etc.
An update: I'm almost there..
/^(\:\:([a-f0-9]{1,4}\:){0,6}?[a-f0-9]{0,4}|[a-f0-9]{1,4}(\:[a-f0-9]{1,4}){0,6}?\:\:|[a-f0-9]{1,4}(\:[a-f0-9]{1,4}){1,6}?\:\:([a-f0-9]{1,4}\:){1,6}?[a-f0-9]{1,4})(\/\d{1,3})?$/i
I am, in this case restricted to using perl's regex.
This contains a patch to Regexp::Common demonstrating a complete, accurate, tested IPv6 regex. Its a straight translation of the IPv6 grammar. Regexp::IPv6 is also accurate.
More importantly, it contains a test suite. Running it with your regex shows you're still a ways off. 10 out of 19 missed. 1 out of 12 false positives. IPv6 contains a lot of special shorthands making it very easy to get subtly wrong.
Best place to read up on what goes into an IPv6 address is RFC 3986 section 3.2.2.