正则表达式挑战:捕获特定行中的所有数字
RegEx Challenge: Capture all the numbers in a specific row
假设我们有这段文字:
...
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 解决方案,但稍后会 post PHP 接收。然而,python 正则表达式和 php 非常相似。
(?<=settingsB=)(\d+(?:\.\d+)?(?:, )?)+
Python:
import re
subject = """
...
settingsA=9, 4.2
settingsB=3, 1.5, 9, 2, 4, 6
settingsC=8, 3, 2.5, 1
...
"""
rx = re.compile(r"(?<=settingsB=)(\d+(?:\.\d+)?(?:, )?)+", re.IGNORECASE)
result = rx.search(subject)
if result:
numString = result.group()
for n in [f.strip() for f in numString.split(',')]:
print(n)
PHP
$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
您可以在所需部分使用 PCRE 正则表达式之前使用 \G
anchor to glue matches to the end of a previous match. This pattern which also uses \K
to reset。
(?:settingsB *=|\G(?!^) *,) *\K[\d.]+
(?:
开一个non-capturing group交替
- 匹配
settingsB
,然后是 *
任意数量的 space,然后是文字 =
|\G(?!^)
或从上一场比赛结束但未开始的地方继续
*,
并匹配前面有可选 space 的逗号
)
交替结束(非捕获组)
*\K
可选后重置 space
[\d.]+
匹配一位或多位数字和句点。
如果序列包含制表符或换行符,请使用 \s
作为 whitespace 字符 而不是 space.
See demo at regex101 or PHP demo at eval.in
or this more compatible pattern with use of a capturing group 而不是 \K
,它应该适用于支持 \G
锚点(Java、.NET、Ruby 的任何正则表达式风格。 .)
假设我们有这段文字:
...
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 解决方案,但稍后会 post PHP 接收。然而,python 正则表达式和 php 非常相似。
(?<=settingsB=)(\d+(?:\.\d+)?(?:, )?)+
Python:
import re
subject = """
...
settingsA=9, 4.2
settingsB=3, 1.5, 9, 2, 4, 6
settingsC=8, 3, 2.5, 1
...
"""
rx = re.compile(r"(?<=settingsB=)(\d+(?:\.\d+)?(?:, )?)+", re.IGNORECASE)
result = rx.search(subject)
if result:
numString = result.group()
for n in [f.strip() for f in numString.split(',')]:
print(n)
PHP
$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
您可以在所需部分使用 PCRE 正则表达式之前使用 \G
anchor to glue matches to the end of a previous match. This pattern which also uses \K
to reset。
(?:settingsB *=|\G(?!^) *,) *\K[\d.]+
(?:
开一个non-capturing group交替- 匹配
settingsB
,然后是*
任意数量的 space,然后是文字=
|\G(?!^)
或从上一场比赛结束但未开始的地方继续*,
并匹配前面有可选 space 的逗号
)
交替结束(非捕获组)*\K
可选后重置 space[\d.]+
匹配一位或多位数字和句点。
如果序列包含制表符或换行符,请使用 \s
作为 whitespace 字符 而不是 space.
See demo at regex101 or PHP demo at eval.in
or this more compatible pattern with use of a capturing group 而不是 \K
,它应该适用于支持 \G
锚点(Java、.NET、Ruby 的任何正则表达式风格。 .)