我的文本部分可能包含美元金额(可能以美元符号为前缀,也可能不包含美元符号)和IP地址。我需要一个正则表达式来识别美元金额,但不匹配 IP 地址的部分。
例如,如果文本是:
12.34 56.78.90.12 34.56
我的开始尝试是:
([1-9]d*.d{2})
这是我想要匹配的,但它匹配部分 IP 地址。然后我尝试:
[^.]([1-9]d*.d{2})[^.]
但这种情况在几乎所有情况下都更糟。
正则表达式需要匹配"12.34"和"34.56",但不能匹配"56.78"或"90.12"。任何帮助将不胜感激。
另一种与 REGEX 不同的方法是假设每个元素之间有一个空格(dollar amount or ip address)
是按空格分解元素并获取只有一个点的元素列表。
$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);
结果:
Array ( [0] => 12.34 [2] => 34.56 )
使用环顾断言和单词边界锚点来确保匹配项周围没有点:
(?<!.)b[1-9]d*.d{2}b(?!.)
在 regex101.com 上实时测试。
(?<=^|[^d.])d+.d+(?=[^d.]|$)
它基本上试图匹配这个:
d+.d+
当字符串的开头(^
)或不是数字或点([^d.]
)的东西在它后面,字符串的结尾($
)或不是数字或点的东西([^d.]
)在它后面。
在这里试试。
使用不合格的(*SKIP)(*FAIL)
模式的执行速度将是当前发布的其他正则表达式模式的两倍多。
/d{1,3}.d{1,3}.d{1,3}.d{1,3}(*SKIP)(*FAIL)|$?[1-9]d*.d{2}/
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- IP address ^^^^^^^^^^^^^^^- currency amount
这将首先查找并取消 IP 地址的资格,然后再尝试将您的货币值与可选的前导美元符号匹配。 此模式允许您在不使用捕获组的情况下匹配您的美元金额 -- 这将提高性能并减少输出阵列膨胀preg_match_all()
模式演示链接
代码:(PHP演示)
$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');
输出:
array (
0 => '12.34',
1 => '34.56',
2 => '$99999.99',
)