仅捕获以 's_' 开头并包含数字和字母混合的字符串中的数字

Capture only the numbers from a string beginning with 's_' and containing a mix of numbers and letters

我想从此字符串中提取所有数字:'s_0a1f2d4e3c10b'。字符串必须遵循此模式 's_NumberLetterNumberLetter...' 我写了这个匹配整个字符串的正则表达式:

/^q_(?:\d+[a-f])+$/

问题是我不知道如何只捕获数字。当我在 \d+ 两边加上方括号时,正则表达式只匹配最后一个数字 (10)。 这是带方括号的正则表达式:

^q_(?:(\d+)[a-f])+$

当然我可以使用 preg_match_all('/\d+/', 's_0a1f2d4e3c10b', $matches) 但我希望字符串以 's_' 开头并且我只想使用一个正则表达式(如果可能的话)。

我想要的 s_0a1f2d4e3c10b 输出:

array(0, 1, 2, 4, 3, 10)

您可以使用 preg_replace,像这样:

$count = null;
$returnValue = preg_replace('/[^0-9]+/', '', 's_0a1f2d4e3c10b', -1, $count);

这将从字符串中删除所有非数字字符。

$returnValue 将包含 '0124310'$count 将包含 7(删除的字符数)

不确定您想要的是哪个结果,因为您似乎想要保留 s_,但将数字(不是数字)分隔成值。它要么是一个字符串,要么是一个数字列表,不能两者兼而有之。

preg_match_all('/s_\d+|\d+/', 's_0a1f2d4e3c10b', $matches) 将 return 一个数组,第一个值在开头保留 s_
preg_match_all('/s_\d+|\d+/', 's_0a1f2d4e3c10b', $matches) 将 return 一个数组,第一个值是 只有 s_ 然后后续值是数字。
您建议的 preg_match_all('/\d+/', 's_0a1f2d4e3c10b', $matches) 将仅 return 数组中的数字,如果您将它们连接到字符串,则可以添加 s_ 前缀。

您需要正则表达式中的“继续”元字符 (\G) 才能在单个 preg_ 调用中干净地执行此任务。

只有当子字符串以 s_ 开头时才能开始匹配。然后匹配只能在坚持交替数字和小写字母模式的情况下继续。

\G 实际上允许从字符串的开头或最后匹配结束的位置开始匹配。要拒绝从字符串开头匹配的功能,请添加包含插入符号 ((?!^)) 的否定前瞻。

\K 表示重新开始这个全字符串匹配(或者换句话说,“忘记”任何以前匹配的字符)。这避免了使用捕获组,否则会不必要地膨胀匹配的输出数组。

代码:(Demo)

$tests = [
    'This string s_0a1f2d4e3c10b is foo.',
    's_1a23b456c789',
    'b_9d9d9d9d9d',
    's_1e2f3a4b'
];

foreach ($tests as $test) {
    var_export(
        preg_match_all(
            '~(?:s_|\G(?!^)[a-z]+)\K\d+~',
            $test,
            $matches
        )
        ? $matches[0]
        : []
    );
    echo "\n---\n";
}

输出:

['0', '1', '2', '4', '3', '10']
---
['1', '23', '456', '789']
---
[]
---
['1', '2', '3', '4']
---