如何在PHP中使用单个正则表达式从字符串中提取所有匹配项?

4
我希望用PHP的正则表达式将所有匹配的模式插入到单个数组中。
例如,我有以下文本:
计算 F 1a5 5W13 153w135 1E55 12_5 1.56 1M55
我的php代码如下:
$txt="calculated 1a5 5W13 153w135 1E55 12_5 1.56 1M55";
preg_match_all("/calculated F( ([\d\w_\.]+))+/s",$txt,$matches);
print_r($matches);

我需要像这样的东西:

Array ( [0] =>1a5, [1]=> 5W13, [2]=>  153w135, [3]=>  1E55, [4]=>  12_5, [5]=>  1.56, [6]=> 1M55)

我该如何在Javascript或Jquery中实现?正则表达式代码是否在http://regexr.com上有效? - Huseyin
https://regex101.com/r/G6mIVp/2 可能是更好的解释。 - Huseyin
@sln 您的回答对我非常实用和有用。但在PHP中使用正则表达式是最佳方法。 - Huseyin
3个回答

5
您可以使用以下的正则表达式解决方案:
$txt="calculated F 15 513 153135 155 125 156 155";
preg_match_all("/(?:\G(?!\A)|calculated(?:\s+F)?)\s*\K[\w.]+/",$txt,$matches);
print_r($matches[0]);

请查看正则表达式演示
此外,请查看PHP演示
请注意,这基本上是您的正则表达式加上一个自定义的\G边界,以匹配添加了特定模式后的连续匹配。请注意,您的[\d\w_\.][\w.]相同,因为\w匹配\d_所匹配的内容。 模式细节
- (?:\G(?!\A)|calculated(?:\s+F)?) - 上一次匹配结束(\G(?!\A), \G只匹配字符串的开头或上一次匹配的结尾,因此,(?!\A)排除了字符串开头位置) 或者calculated + 1个或多个空格 + F(与calculated(?:\s+F)?分支匹配) - \s* - 零个或多个空格 - \K - 匹配重置操作符 - [\w.]+ - 一个或多个数字、字母、_.字符。

我需要它的某个复杂版本。我修改了问题,您能否重新看一下? - Huseyin
2
@Huseyin:我看到你更新了一个问题,但是只改变了示例字符串和示例输出。你没有提供确切的要求。现在我不知道你需要什么。你使你的问题不清楚。现在,我只能猜测你想匹配特定字符串后的1个或多个非空格字符序列。尝试将最后一个\d+替换为\S+并使\s+F可选。我的解决方案仍适用于您的新场景。 - Wiktor Stribiżew
我使用了你提供的模式逻辑更新了答案。真心希望这能有所帮助。 - Wiktor Stribiżew
哇,太棒了。你能帮我在 https://regex101.com/r/G6mIVp/3 中选择只有 LA701、LIPIJAP、LIPIKOR 和 LREX 吗? - Huseyin
感谢您的努力。我想从https://regex101.com/r/G6mIVp/3获取数组(“LA701”,“LIPIJAP”,“LIPIKOR”,“LREX”)。 - Huseyin
1
@Huseyin:请查看(?:Variables are:|\G(?!\A))\h+\K\w+ - Wiktor Stribiżew

2

一种更简单的方法是将值进行批量匹配,然后在空格上进行split()分割。

代码示例:

$txt="calculated F 15 513 153135 155 125 156 155  ";
if ( preg_match('~calculated F \s*(\d+(?:\s*\d+)*)~', $txt, $matches) )
    print_r( preg_split( '~\s+~', $matches[1] ) );

https://ideone.com/pbCWgU

Output

Array
(
    [0] => 15
    [1] => 513
    [2] => 153135
    [3] => 155
    [4] => 125
    [5] => 156
    [6] => 155
)

这是一个非常出色的解决方案,但我需要基于正则表达式而不是分割。 - Huseyin

1

在问题细节更新后,我更新了我的答案...

如果您知道 calculated 将在字符串的开头,其余部分是一组以空格分隔的有效值,则建议不要使用正则表达式,因为它速度较慢 / 效率较低。

这就是你需要的全部:

$txt="calculated 1a5 5W13 153w135 1E55 12_5 1.56 1M55";
var_export(array_slice(explode(' ',$txt),1));

这将会把字符串按照空格拆分,并从拆分后的结果数组中移除第一个元素。
输出:
array (
  0 => '1a5',
  1 => '5W13',
  2 => '153w135',
  3 => '1E55',
  4 => '12_5',
  5 => '1.56',
  6 => '1M55',
)

如果您的输入字符串在“calculated”后面可能会有“F”,请更新您的问题——因为这在您的问题中是不一致的,而且这是至关重要的信息。
当字符串/数组操作提供相同级别的准确性并具有更高的效率时,正则表达式过于复杂了。
在您的情况下使用正则表达式的唯一逻辑原因是,如果“calculated”可能会被一个不需要的非空格字符(如“F”)所跟随。此时,您可以使用这个简单/有效的模式:
$txt="calculated F 1a5 5W13 153w135 1E55 12_5 1.56 1M55";
var_export(preg_match_all('/\K\d\S*/',$txt,$out)?$out[0]:'no match');
// output same as previous method

这种方法会从每个数字开始进行全字符串匹配,直到遇到一个空格字符为止。

@Huseyin 我刚好重新访问这个页面,因为我在我的另一台电脑上忘记关闭。我看到你已经更新了你的输入数据。考虑到你的新的输入数据,我提供了两种简单/准确/优化方法,它们比其他方法表现更出色。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接