正则表达式 - 匹配第二个结束标记而不是第一个

Regex - Matching with the second closing tag instead of the first one

我正在尝试找到正确的模式来匹配 [CODE] 块中的一个或多个 [U]。

以下是包含我要匹配的标签的示例结构。模式应该找到第二个 [CODE] 块。

[CODE]
    ...there is no U tag here...
[/CODE]

[U]out of the code tags[/U]

[CODE]
    ...something else...
    [U]inside the code tags[/U]
    ...something else...
[/CODE]

我正在使用以下模式:

/\[CODE\](.*)\[U\](.*)\[\/U\](.*)\[\/CODE\]/gisU

然而它与中间两个 CODE 块中的 U 标记匹配,认为第一个 [CODE] 和最后一个 [/CODE] 是它正在寻找的。

我怎样才能让它工作,所以它会看到第一个结束标记 [/CODE],并且不会与外部 [U] 匹配,而是与第二个 [CODE] 块内的匹配?

注意:我尝试使用 ([^[/CODE]]*) 与模式中 [U] 之前的结束标记 [/CODE] 不匹配,但无法使其工作。显然不太擅长这个。

如有任何帮助,我们将不胜感激。谢谢!

这是一个解决方案preg_match_all:

$input = "[CODE]\n...there is no U tag here...\n[/CODE]\n\n[U]out of the code tags[/U]\n\n[CODE]\n...something else...\n[U]inside the code tags[/U]\n\n...something else...\n[/CODE]";
preg_match_all("/\[CODE\]((?!\[\/?CODE\]).)*\[U\].*?\[\/CODE\]/s", $input, $matches);
print_r($matches[0]);

Array
(
    [0] => [CODE]
...something else...
[U]inside the code tags[/U]

...something else...
[/CODE]
)

关于 PHP 代码本身不需要过多提及,除了我们使用 s 标志和 preg_match_all,以确保我们 运行 中的正则表达式全点模式。这是必需的,因为您的内容跨越多行。

这里是对所用正则表达式的解释:

\[CODE\]             match an initial [CODE] tag
((?!\[\/?CODE\]).)*  consume anything so long it is not an opening OR closing [/CODE] tag
\[U\]                consume an opening [U] tag
.*?                  then consume anything up until the first
\[\/CODE\]           closing [/CODE] tag

上面的大部分正则表达式都很简单,除了以下部分:

((?!\[\/?CODE\]).)*

这使用了一种叫做 tempered 点的东西,它表示一次向前迈出一步,在每一步检查我们没有遇到空位 [CODE] 或关闭 [/CODE] 标签。这确保我们匹配 [CODE]...[/CODE] 标签集中的 [U] 标签。

请注意,我的回答假设您的输入格式正确,即除了您向我们展示的内容之外没有标签嵌套,并且每个开始标签都有一个适当的结束标签。如果您需要在此基础上进行验证,那么您将不得不做更多的工作。