1

这是内容片段:

这是一个样本的内容。
[md] 特殊内容片段 [/md]

这是更多的内容。

我想要的是一个preg_match_all表达式,它可以从上述内容中获取并给我以下内容:

[md] 特殊内容片段 [/md]

我试过这个:

$pattern ="/\[^[a-zA-Z][0-9\-\_\](.*?)\[\/^[a-zA-Z][0-9\-\_]\]/";
preg_match_all($pattern, $content, $matches);

但它给出了一个空白数组。有人可以帮忙吗?

4

3 回答 3

1
$pattern = "/\[md\](.*?)\[\md\]/";

一般来说

$pattern = "/\[[a-zA-Z0-9\-\_]+\](.*?)\[\/[a-zA-Z0-9\-\_]+\]/";

甚至更好

$pattern = "/\[\w+\](.*?)\[\/\w+\]/";

并将开始标签与结束标签匹配:

$pattern = "/\[(\w+)\](.*?)\[\/\1\]/";

(请注意,“标签”名称随后会在匹配数组中返回。)

于 2013-06-14T10:49:56.273 回答
1

你可以使用这个:

$pattern = '~\[([^]]++)]\K[^[]++(?=\[/\1])~';

解释:

~          #delimiter of the pattern
\[         #literal opening square bracket (must be escaped)

(          #open the capture group 1
  [^]]++     #all characters that are not ] one or more times
)          #close the capture group 1

]          #literal closing square bracket (no need to escape)

\K         #reset all the match before

[^[]++     #all characters that are not [ one or more times

(?=        #open a lookahead assertion (this doesn't consume characters)
  \[/        #literal opening square bracket and slash
  \1         #back reference to the group 1
  ]          #literal closing square bracket
)          #close the lookhead
~

这种模式的兴趣:

结果是整个匹配,因为我之前已经重置了所有匹配,\K并且因为前瞻断言,在你正在寻找的东西之后,不消耗字符并且不在匹配中。

字符类被定义为负数,因此写起来更短,也更宽松(你不关心里面必须有什么字符)

该模式检查开始和结束标记是否与捕获组\反向引用的系统相同。

限制:

此表达式不处理嵌套结构(您不需要)。如果您需要,请编辑您的问题。

对于嵌套结构,您可以使用:

(?=(\[([^]]++)](?<content>(?>[^][]++|(?1))*)\[/\2]))

如果您的 bbcode 中允许使用属性:

(?=(\[([^]\s]++)[^]]*+](?<content>(?>[^][]++|(?1))*)\[/\2]))

如果允许自动关闭 bbcode 标签:

(?=((?:\[([^][]++)](?<content>(?>[^][]++|(?1))*)\[/\2])|\[[^/][^]]*+]))

笔记:

换句话说,前瞻意味着:“跟随

我使用所有格量词++_ _(?>..)

在嵌套结构的模式中,斜杠不会被转义,要使用它们,您必须选择一个不是斜杠 ( ~, #, `) 的分隔符。

嵌套结构的模式使用递归(即(?1)),您可以在此处此处获得有关此功能的更多信息。

于 2013-06-14T10:55:27.787 回答
0

更新:
如果您可能正在使用嵌套的“标签”,我可能会选择这样的东西:

$pattern = '/(\[\s*([^\]]++)\s*\])(?=(.*?)(\[\s*\/\s*\2\s*\]))/';

正如您可能知道的那样,这与 CasimiretHippolyte 的建议没有什么不同(只有他的正则表达式 AFAIKT 不会在如下场景中捕获外部标签:)

his is content that is a sample.
[md] Special Content [foo]Piece[/foo] [/md]

This is some more content.

然而,使用这个表达式,$matches看起来像:

大批 (
  0 =>
  大批 (
    0 => '[md]',
    1 => '[foo]',
  ),
  1 =>
  大批 (
    0 => '[md]',
    1 => '[foo]',
  ),
  2 =>
  大批 (
    0 => 'md',
    1 => '富',
  ),
  3 =>
  大批 (
    0 => ' 特殊内容 [foo]Piece[/foo] ',
    1 => '片',
  ),
  4 =>
  大批 (
    0 => '[/md]',
    1 => '[/foo]',
  ),
)

一个相当简单的模式来匹配看起来像这样的所有子字符串[foo]sometext[/foo]

$pattern = '/(\[[^\/\]]+\])([^\]]+)(\[\s*\/\s*[^\]]+\])/';

if (preg_match_all($pattern, $content, $matches))
{
    echo '<pre>';
    print_r($matches);
    echo '</pre>';
}

输出:

大批 (
  0 =>
  大批 (
    0 => '[md] 特殊内容片段 [/md]',
  ),
  1 =>
  大批 (
    0 => '[md]',
  ),
  2 =>
  大批 (
    0 => '特殊内容片段',
  ),
  3 =>
  大批 (
    0 => '[/md]',
  ),
)

这种模式是如何工作的:它分为三组。
第一个:(\[[^\/\]]+\])匹配开头和结尾[],中间的所有内容既不是右括号也不是正斜杠。
第二个: '([^]]+)' 匹配第一个非字符组之后的每个字符[
第三个:(\[\s*\/\s*[^\]]+\])匹配一个开头[,后跟零个或多个空格,一个正斜杠,再后跟零个或多个空格,以及任何其他不是的字符]

如果你想匹配一个特定的结束标签,但保持相同的三个组(第四个),使用这个(稍微复杂一点)表达式:

$pattern = '/(\[\s*([^\]]+?)\s*\])(.+?)(\[\s*\/\s*\2\s*\])/';

这将返回:

大批 (
  0 =>
  大批 (
    0 => '[md] 特殊内容片段 [/md]',
  ),
  1 =>
  大批 (
    0 => '[md]',
  ),
  2 =>
  大批 (
    0 => 'md',
  ),
  3 =>
  大批 (
    0 => '特殊内容片段',
  ),
  4 =>
  大批 (
    0 => '[/md]',
  ),
)

请注意,第 2 组(我们在表达式中使用 as 的\2那个)是“标记名”本身。

于 2013-06-14T10:54:50.000 回答