We can write the numbers you are looking for like this:
re_n = (?:[^x]|^)\d\d\d(?:[^ip]|$)
Then the whole expression is:
^(?!.*re_n.*re_n.*$).*(re_n)
which basically eliminates double numbers using a negative lookahead following the line start anchor, then matches a valid number.
The interpolated expression looks ugly:
/^(?!.*(?:(?:[^x]|^)\d\d\d(?:[^ip]|$)).*(?:(?:[^x]|^)\d\d\d(?:[^ip]|$)).*$).*((?:(?:[^x]|^)\d\d\d(?:[^ip]|$)))/
This Perl code:
my $re_n = qr/(?:[^x]|^)\d\d\d(?:[^ip]|$)/;
while (<DATA>) { chomp;
if (/^(?!.*$re_n.*$re_n.*$).*($re_n)/) {
print "$_: $1\n";
} else {
print "$_: NONE\n";
}
}
__DATA__
This is 321 an example.
321 also
including 321 //basically not possible, but can't hurt.
this 321 has another group with a p: 122p
this 321 has another group with a I: 123i
this x235 should be ignored cause 123 is what i want to match.
123 is what i want, not x111 or 125p or 999i
in this 111 case there is no solution 555
Produces:
This is 321 an example.: 321
321 also: 321
including 321 //basically not possible, but can't hurt.: 321
this 321 has another group with a p: 122p: 321
this 321 has another group with a I: 123i: 321
this x235 should be ignored cause 123 is what i want to match.: 123
123 is what i want, not x111 or 125p or 999i: 123
in this 111 case there is no solution 555: NONE