In theory that's an ideal task for regexp assertions in Perl code. Unfortunatly such assertions are rather convoluted to do in current day perl, though it does work.
Let's first try the simplified task to find if a number matches an integer that is between 0 and 255 (incl). The lower border is easy, all you need to do is forbid a minus sign. So all you have to do is test if a matched number is below 256.
Here's a demo to see if an integer is below 256:
($\, $,) = ("\n", "\t");
print $_, /\b(\d+)\b(?(?{$1 >= 256})(?!))/ ? 'Y' : 'N' for 0 .. 1000;
This prints, summarized:
0 Y
1 Y
2 Y
...
254 Y
255 Y
256 N
257 N
...
1000 N
So how does it work? First of all, we try to match an integer, using
/\b(\d+)\b/
The "\b" is desired when using assertions, in order to prevent substrings to match instead of the whole. Otherwise, if you have a string "1234", the substring "123" is less than 256 and would match. We can't use that.
The next part is a pattern of the form
(?(condition)yes-pattern)
which will try to match the "yes-pattern" only if the condition (a regex pattern itself) is met. The condition takes the form here:
(?{ code })
which executes code, and which normally always succeeds; but which in this special usage case serves as a switch to conditionally test the following yes-pattern.
And that yes-pattern takes the form
(?!)
which actually is a plain negative lookahead, which essentially says "whatever it is that follows now, it is wrong." So, essentially, it always fails.
The net effect is the condition has to be the wrong way around: it must return true when we want the math to fail. In this example, we have code to test if what is matched is 256 or above, and if so, fail by trying (and failing) to match /(?!)/.
As a whole, we can try matching an 4-dotted quad IP address using the regexp:
/^(\d+)(?(?{$1 >= 256})(?!))\.(\d+)(?(?{$2 >= 256})(?!))\.(\d+)(?(?{$3
+ >= 256})(?!))\.(\d+)(?(?{$4 >= 256})(?!))$/
but we might as well combine the separate conditions into one:
/^(\d+)\.(\d+)\.(\d+)\.(\d+)$(?(?{$1 >= 256 || $2 > 256 || $3 >= 256 |
+|$4 >= 256})(?!))/
Do note that I can leave off the \b anchors, because I have enough other sideconditions: andchors /^/ and /$/, as well as a need to match /\./ next. |