正则表达式 (PCRE):匹配所有以字符串存在为条件的数字

Regex (PCRE): Match all digits conditional upon presence of a string

使用 PCRE,我只想捕获一行中的所有数字,但前提是特定字符串(例如“STRING99”)出现在该行的任何位置。

例如,考虑这两种情况:

a1 STRING99 2b c3d

a1 2b c3d

在第一种情况下,我希望结果为“19923”。 在第二种情况下,我想要一个空结果。

我不确定这是否可能。它可能适用于可变长度的后视,但这在 PCRE 中不受支持。此外,像 (?=.*STRING99.*$)(\D|(\d))* 这样的东西会起作用,但是“重复的捕获组只会捕获最后一次迭代”,这意味着第二个捕获组只捕获最后一个数字。我无法为此找到解决方法。

(这显然不难实现连续2次正则表达式运算,但我希望它在一个公式中。)

我们可以使用带有回调函数的正则表达式替换:

$output = preg_replace_callback('/^.*\bSTRING99\b.*$/', function ($match) {
    return preg_replace("/\D+/", "", $match[0]);
}, 'a1 STRING99 2b c3d');

echo $output;   // prints 1992

这里的做法是首先只匹配包含STRING 99的输入。然后在这样的匹配上,我们去掉所有非数字字符。不匹配将不会完成此替换。

您可以使用

(?:\G(?!^)|^(?=.*STRING99)|^.*(*ACCEPT))\d*\K\D+

请参阅 regex demo(我将 \D 替换为 [^\d\n] 仅出于演示目的,因为测试是针对多行字符串执行的)。

详情

  • (?:\G(?!^)|^(?=.*STRING99)|^.*(*ACCEPT)) - 如果在任何 0+ 个字符之后有 STRING99 字符串(参见 ^(?=.*STRING99))或(否则)整个字符串与 ^.* 匹配并返回成功匹配(不进一步解析模式)
  • \d* - 消耗了 0 个或更多数字
  • \K - 并从匹配内存缓冲区中丢弃
  • \D+ - 1 个或多个 non-digit 个字符(最终将被删除)。

您可以在 preg_replace:

中使用此 PCRE 正则表达式
^(?!.*STRING99).*(*SKIP)|\D+

RegEx Demo

正则表达式详细信息:

  • ^: 开始
  • (?!.*STRING99):Lokahead 检查输入
  • 中是否有STRING99
  • .*(*SKIP): 匹配输入的剩余部分直到结束并跳过它
  • |: 或
  • \D+: 匹配 1+ non-digit

PHP代码:

$repl = preg_replace('~^(?!.*STRING99).*(*SKIP)|\D+~', '', $str);