正则表达式查找美元金额但不匹配IP地址

I have sections of text that may contain both dollar amounts, that may or may not be prepended with a dollar sign, and IP addresses. I need a regular expression that will identify the dollar amounts but not match portions of the IP addresses.

For example if the text is:

12.34 56.78.90.12 34.56

My starting attempt was:

([1-9]\d*\.\d{2})

This is what I want to match, but it matches parts of the IP addresses. I then tried:

[^\.]([1-9]\d*\.\d{2})[^\.]

But this was worse on almost all cases.

The regular expression needs to match "12.34" and "34.56", but not "56.78" or "90.12". Any help would be appreciated.

Use lookaround assertions and word boundary anchors to make sure that there are no dots around your match:

(?<!\.)\b[1-9]\d*\.\d{2}\b(?!\.)

Test it live on regex101.com.

(?<=^|[^\d.])\d+\.\d+(?=[^\d.]|$)

It's basically trying to match this:

\d+\.\d+

when either the start of the string (^) or something not a digit or a dot ([^\d.]) is behind it and either the end of the string ($) or something not a digit or a dot ([^\d.]) is after it.

Try it here.

Another approach different to REGEX assuming there is a space between each element (dollar amount or ip address) would be to explode the element by space and get a list of the elements that has only one dot.

$text = "12.34 56.78.90.12 34.56";

$dollars_amt = array_filter(explode(' ', $text), function($s) {
    if (substr_count($s, '.') == 1) {
        return $s;
    }
});

print_r($dollars_amt);

Result:

Array ( [0] => 12.34 [2] => 34.56 )

Using a disqualifying (*SKIP)(*FAIL) pattern will perform more than twice as fast as the other regex pattern currently posted.

/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(*SKIP)(*FAIL)|\$?[1-9]\d*\.\d{2}/
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- IP address   ^^^^^^^^^^^^^^^- currency amount

This will first seek and disqualify IP addresses before trying to match your currency values with optional leading dollar sign. This pattern allows you to match your dollar amounts without using a capture group -- this will improve performance and reduce output array bloat from preg_match_all()

Pattern Demo Link

Code: (PHP Demo)

$string='12.34 56.78.90.12 34.56 156.8.90.2 $99999.99';
var_export(preg_match_all('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(*SKIP)(*FAIL)|\$?[1-9]\d*\.\d{2}/',$string,$out)?$out[0]:'fail');

Output:

array (
  0 => '12.34',
  1 => '34.56',
  2 => '$99999.99',
)