使用 PHP 正则表达式命名捕获的数组

Array named capture using PHP regex

如果命名捕获匹配多次,是否可以检索所有匹配项?

例子

<?php

$string = 'TextToMatch [some][random][tags] SomeMoreMatches';
$pattern = "!(TextToMatch )(?P<tags>\[.+?\])+( SomeMoreMatches)!";

preg_match($pattern, $string, $matches);
print_r($matches);

结果是

Array
(
    [0] => TextToMatch [some][random][tags] SomeMoreMatches
    [1] => TextToMatch 
    [tags] => [tags]
    [2] => [tags]
    [3] =>  SomeMoreMatches
)

有可能得到类似

的东西
Array
(
    [0] => TextToMatch [some][random][tags] SomeMoreMatches
    [1] => TextToMatch 
    [tags] => Array
        (
            [0] => [some]
            [1] => [random]
            [2] => [tags]
        )
    [2] => Array
        (
            [0] => [some]
            [1] => [random]
            [2] => [tags]
        )
    [3] =>  SomeMoreMatches
)

仅使用 preg_match?


我知道我可以展开标签,但我想知道我是否可以仅使用 preg_match(或类似功能)来做到这一点。


其他例子

$input = "Some text [many][more][other][tags][here] and maybe some text here?";

理想的输出

Array
(
    [0] => Some text [many][more][other][tags][here] and maybe some text here?
    [1] => Some text 
    [tags] => Array
        (
            [0] => [many]
            [1] => [more]
            [2] => [other]
            [3] => [tags]
            [4] => [here]
        )
    [2] => Array
        (
            [0] => [many]
            [1] => [more]
            [2] => [other]
            [3] => [tags]
            [4] => [here]
        )
    [3] =>   and maybe some text here?
)

您需要使用 preg_match_all 并修改 reg exp:

preg_match_all('/(?P<tags>\[.+?\])/', $string, $matches);

只需删除 ) 之后的 + 即可设置一个模式 preg_match_all 进行全局搜索

如果您需要您发布的具体答案,请尝试:

$string = '[some][random][tags]';
$pattern = "/(?P<tags>\[.+?\])/";

preg_match_all($pattern, $string, $matches);

$matches = [
  implode($matches['tags']), end($matches['tags'])
] + $matches;

print_r($matches);

你得到:

Array
(
    [0] => [some][random][tags]
    [1] => [tags]
    [tags] => Array
        (
            [0] => [some]
            [1] => [random]
            [2] => [tags]
        )

)

不,如 Wiktor 所述(, ),仅使用 preg_match

是不可能的

有效的解决方案

<?php

$string = 'TextToMatch [some][random][tags] SomeMoreMatches';
$pattern = "!(TextToMatch )(?P<tags>\[.+?\]+)( SomeMoreMatches)!";

preg_match($pattern, $string, $matches);
$matches[2] = $matches["tags"] = array_map(function($s){return "[$s]";}, explode("][", substr($matches["tags"],1,-1)));
print_r($matches);

由于您在评论中声明您实际上对标签集之前的前导子字符串不感兴趣,并且因为您声明您不一定需要命名的捕获组(我从不使用它们),所以您实际上只需要去掉第一个位,在标签集之后的 space 上拆分字符串,然后拆分标签集中的每个标签。

代码:(Demo)

$split = explode(' ', strstr($input, '['), 2);  // strstr() trims off the leading substring
var_export($split);                     // ^ tells explode to stop after making 2 elements

生产:

array (
  0 => '[many][more][other][tags][here]',
  1 => 'and maybe some text here?',
)

然后最 direct/clean 拆分方括号标签的方法是使用每个右括号 (]) 和每个左括号 ([ 之间的零宽度位置).由于只有正则表达式可以将这些特定位置隔离为分隔符,因此我建议 preg_split().

$split[0] = preg_split('~]\K~', $split[0], -1, PREG_SPLIT_NO_EMPTY);
var_export($split);       ^^- release/forget previously matched character(s)

这是最终输出:

array (
  0 => 
  array (
    0 => '[many]',
    1 => '[more]',
    2 => '[other]',
    3 => '[tags]',
    4 => '[here]',
  ),
  1 => 'and maybe some text here?',
)