PHP preg_match_all:提取命令参数

3

我有以下的LaTeX命令:

\autocites[][]{}[][]{}

[]中的参数是可选项,{}中的参数是必需的。 \autocites命令可以通过其他一组参数进行扩展,例如:

\autocites[a1][a2]{a3}[b1][b2]{b3}
\autocites[a1][a2]{a3}[b1][b2]{b3}[c1][c2]{c3}
...

它还可以这样使用:
\autocites{a}{b}
\autocites{a}[b1][]{b3}
\autocites{a}[][b2]{b3}
...

我想使用PHP中的正则表达式提取其参数。这是我的第一次尝试:
/\\autocites(\[(.*?)\])(\[(.*?)\])(\{(.*?)\})(\[(.*?)\])(\[(.*?)\])(\{(.*?)\})/

虽然如果\autocites只包含三个参数的两组,那么这将有效工作,但我无法弄清如何使其在未知数量的参数情况下正常工作。

我还尝试使用以下表达式:

/\\autocites((\[(.*?)\]\[(.*?)\])?\{(.*?)\}){2,}/

这次我能够匹配更多的参数,但是我不能提取所有的值,因为PHP总是只给我最后三个参数的内容:

Array
(
    [0] => Array
        (
            [0] => \autocites[a][b]{c}[d][e]{f}[a][a]{a}
        )

    [1] => Array
        (
            [0] => [a][a]{a}
        )

    [2] => Array
        (
            [0] => [a][a]
        )

    [3] => Array
        (
            [0] => a
        )

    [4] => Array
        (
            [0] => a
        )

    [5] => Array
        (
            [0] => a
        )

)

非常感谢您的帮助。


2
可能更简单的方法是匹配整个命令,包括随机的 (\{.\}|\[.\])* 变化。然后使用第二个 preg_match_all 提取各个参数。或者使用 ?(DEFINE) 或至少 /x 修饰符来制作可管理的正则表达式。 - mario
1个回答

2
你需要分两步来完成这个操作。只有.NET可以检索任意数量的捕获组。在其他所有语言中,结果的捕获组数量由模式中组的数量固定(重复一个组只会覆盖之前的捕获)。因此,首先匹配整个内容以获取参数,然后再进行第二步提取。
preg_match('/\\\\autocites((?:\{[^}]*\}|\[[^]]*\])+)/', $input, $autocite);
preg_match_all('/(?|\{([^}]*)\}|\[([^]]*)\])/', $autocite[1], $parameters);
// $parameters[1] will now be an array of all parameters

工作 演示。

使用稍微复杂一些的方法和锚点\G,我们也可以采用任意数量的匹配而不是捕获来一次性完成所有操作:

preg_match_all('/
    (?|             # two alternatives whose group numbers both begin at 1
      \\\\autocites  # match the command
      (?|\{([^}]*)\}|\[([^]]*)\])
                    # and a parameter in group 1
    |               # OR
      \G            # anchor the match to the end of the last match
      (?|\{([^}]*)\}|\[([^]]*)\])
                    # and match a parameter in group 1
    )
    /x',
    $input,
    $parameters);
// again, you'll have an array of parameters in $parameters[1]

请注意,采用这种方法 - 如果您的代码中有多个 autocites,则会在单个列表中获取所有命令的所有参数。有一些方法可以缓解这种情况,但我认为在这种情况下第一种方法更清晰。
如果您想能够区分可选和必需参数(使用任何方法),请捕获括号/大括号的开头或结尾,并检查该字符以确定它是哪种类型。

工作演示。


2
在 PHP 中,'\\a' 表示的是 \a,如果要得到 \\a,需要写成 '\\\\a'。或者你可以使用 <<<'quoting'。(我想是这样的。):-p - Qtax

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