[英]regex optional repetitive group
假设以下字符串:
some text here [baz|foo] and here [foo|bar|baz] and even here [option].
我设法只通过这个丑陋的正则表达式( Regex101.com demo )进行匹配:
/(?:
\[
(?:
\|?
([^\|\[\]]+)
)?
(?:
\|?
([^\|\[\]]+)
)?
(?:
\|?
([^\|\[\]]+)
)?
\]
)/ugx
关键是我需要用方括号将比赛分组。 所以目前我确实有需要的结果:
[
{
"match": 1,
"children": [
{
"group": 1,
"start": 16,
"end": 19,
"value": "baz"
},
{
"group": 2,
"start": 20,
"end": 23,
"value": "foo"
}
]
},
{
"match": 2,
"children": [
{
"group": 1,
"start": 35,
"end": 38,
"value": "foo"
},
{
"group": 2,
"start": 39,
"end": 42,
"value": "bar"
},
{
"group": 3,
"start": 43,
"end": 46,
"value": "baz"
}
]
},
{
"match": 3,
"children": [
{
"group": 1,
"start": 63,
"end": 69,
"value": "option"
}
]
}
]
结果是正确的,但是正则表达式限于模式中重复块的数量。 有什么解决方法可以使其与方括号内的所有选项匹配?
您将无法在模式内递归地生成捕获组,因为引擎无法为您提供这种功能。 这样说,您有两种选择:
|
在您的输入字符串中。 这样,您可以使用([^][|]+)
大多数可能重复模式构建单个正则表达式,从而根据需要进行组匹配:
$pattern = (function () use ($string) {
$array = [];
for ($i = 0; $i <= substr_count($string, "|"); $i++) {
$array[] = $i == 0 ? '([^][|]+)' : '([^][|]+)?';
}
return implode("\|?", $array);
})();
通过输入类似以下的输入字符串:
some text here [baz] and here [you|him|her|foo|bar|baz|foo|option|test] and even here [another].
煮熟的正则表达式为:
~\[([^][|]+)\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?]~
然后您可以简单地使用它:
preg_match_all("~\[$pattern]~", $string, $matches, PREG_SET_ORDER);
这是一种变通方法,它表明您可以节省时间并避免仅构建正则表达式时会头疼,并且正则表达式并非始终简单易用的解决方案。
上述解决方法不能带来可靠的解决方案。 它正在做很多不需要的工作。 下面的代码确实适合您的工作:
// Capture strings between brackets
preg_match_all('~\[([^]]+)]~', $string, $matches);
$groups = [];
foreach ($matches[1] as $values) {
// Explode them on pipe
$groups[] = explode('|', $values);
}
输出为:
Array
(
[0] => Array
(
[0] => baz
)
[1] => Array
(
[0] => you
[1] => him
[2] => her
[3] => foo
[4] => bar
[5] => baz
[6] => foo
[7] => option
[8] => test
)
[2] => Array
(
[0] => another
)
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.