Php 正则表达式挑战:捕获特定行中的所有数字
假设我们有以下文本:Php 正则表达式挑战:捕获特定行中的所有数字,php,regex,text,notepad++,pcre,Php,Regex,Text,Notepad++,Pcre,假设我们有以下文本: ... settingsA=9, 4.2 settingsB=3, 1.5, 9, 2, 4, 6 settingsC=8, 3, 2.5, 1 ... 问题是如何使用单个步骤捕获特定行中的所有数字? 单步是指: 单一正则表达式模式 单次操作(无回路或拆分等) 在一个数组中捕获所有匹配项 假设我想捕获以settingsB=开头的行中存在的所有数字。最终结果应如下所示: 3 1.5 9 2 4 6 我失败的尝试: <?php $subject =
...
settingsA=9, 4.2
settingsB=3, 1.5, 9, 2, 4, 6
settingsC=8, 3, 2.5, 1
...
问题是如何使用单个步骤捕获特定行中的所有数字?
单步是指:
- 单一正则表达式模式
- 单次操作(无回路或拆分等)
- 在一个数组中捕获所有匹配项
settingsB=
开头的行中存在的所有数字。最终结果应如下所示:
3
1.5
9
2
4
6
我失败的尝试:
<?php
$subject =
"settingsA=9, 4.2
settingsB=3, 1.5, 9, 2, 4, 6
settingsC=8, 3, 2.5, 1";
$pattern = '([\d\.]+)(, )?' // FAILED!
$pattern = '(?:settingsB=)(?:([\d\.]+)(?:, )?)' // FAILED!
$pattern = '(?:settingsB=)(?:([\d\.]+)(?:, )?)+' // FAILED!
$pattern = '(?<=^settingsB=|, )([\d+\.]+)' // FAILED!
preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
if ($matches) {
print_r($matches);
}
?>
更新1:@Saleem的示例使用了多个步骤而不是单个步骤,很遗憾。我并不是说他的例子不好(它实际上是有效的),但我想知道是否有其他方法可以做到这一点,以及如何做到这一点。有什么想法吗
更新2:@bobble bubble为这一挑战提供了完美的解决方案 这里是python解决方案,但稍后将发布PHP rx。然而,python正则表达式和php非常相似
(?<=settingsB=)(\d+(?:\.\d+)?(?:, )?)+
可以使用将匹配项粘附到上一个匹配项的末尾。此模式也在所需部件与PCRE regex flavor一起使用之前使用
(?:settingsB *=|\G(?!^) *,) *\K[\d.]+
打开一个用于替换的(?:
- 匹配
,后跟settingsB
任意大小的空格,后跟literal*
=
或在上一个匹配结束但未开始的位置继续|\G(?!^)
并匹配前面带有可选空格的逗号*,
交替结束(非捕获组))
在可选空格后重置*\K
匹配一个或多个数字和句点[\d.]+
使用替代的
\K
应该可以在任何支持\G
锚(Java、.NET、Ruby…)的正则表达式风格中工作,请提及您的环境、语言。e、 PHP、python、java、JavaScript等,甚至编辑器、记事本++我猜是一个通用引擎,没有语言,除了正则表达式。是的,但这将是一个多阶段的解决方案。capture+tokenizerI发布了python解决方案,因为php目前不可用。但是python和php正则表达式非常相似,我将其粘贴到regex101.com中,它只匹配最后一个数字,即使正则表达式设置为python也是如此。“知道为什么吗?”萨利姆,谢谢你的回答,但一定有更好的解决办法。我希望在不拆分的情况下返回数组中的结果,例如(numString.split)
。让正则表达式进行拆分。有什么想法吗?@JerryJeremiah,因为regex101只显示最后一组。请看@OlavH,是的,我同意。应该有更好的解决方案,但在短时间内总比没有好:)只是为了好玩:你知道过早优化是万恶之源一个解决方案是应用两个不同的正则表达式。一个是像最初一样捕获整个字符串,然后在最后一次捕获的结果上应用另一个正则表达式来消除coma`,`简直太完美了!这就是我所说的regex魔术。谢谢你的解决方案。
$subject =
"settingsA=9, 4.2
settingsB=3, 1.5, 9, 2, 4, 6
settingsC=8, 3, 2.5, 1";
$pattern = '/(?<=settingsB=)(\d+(?:\.\d+)?(?:, )?)+/i';
preg_match($pattern, $subject, $matches);
if ($matches) {
$num = explode(",", $matches[0]);
for ($i = 0; $i < count($num); $i++) {
print(trim($num[$i]) . "\n");
}
}
3
1.5
9
2
4
6
(?:settingsB *=|\G(?!^) *,) *\K[\d.]+