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

问题描述 投票:1回答:1

我试图找到正确的模式,以匹配[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]不匹配,但无法使其正常工作。显然不是很擅长这个。

任何帮助将不胜感激。谢谢!

php regex preg-match
1个回答
1
投票

这是一个解决方案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,以确保我们在DOT 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\]).)*

这使用了一种称为钢化点的东西,它表示一次向前迈出一步,检查每一步我们没有遇到开口[CODE]或关闭[/CODE]标签。这确保我们匹配[U]标签集内的[CODE]...[/CODE]标签。

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

© www.soinside.com 2019 - 2024. All rights reserved.