正则表达式过滤BBCode列表

时间:2019-03-08 16:08:50

标签: php regex

我正在尝试改进可处理字符串中的BBCode的旧版PHP代码,目前正遇到列表问题。

当前的列表解决方案执行以下操作:

...
$search[]  = sprintf('~\[%s\](.*)\[/%s\]~smUi', 'list', 'list');
$search[]  = sprintf('~\[%s=(.*)\](.*)\[/%s\]~smUi', 'list', 'list');
$search[]  = sprintf('~\[\%s\]~i', '*');
$replace[] = '$1';
$replace[] = '$2';
$replace[] = '';
...
return preg_replace($search, $replace, $string);

当字符串类似于

时,此方法可以正常工作
[list]
  [*]Item 1
  [*]Item 2
  [*]Item 3
[/list]

但是,如果[*]不在列表中,并且也会因以下内容而失败,则会删除[list] [*][list] [*]Item 1.1 [*]Item 1.2 [*]Item 1.3 [/list] [*]Item 2 [*]Item 3 [/list]

[list]

是否甚至可以使用RegExp去除[list=1]标签中的[/list][*] + hostnamectl set-hostname myhost.test.com标签,如果它们在列表中?

1 个答案:

答案 0 :(得分:0)

您可以使用

$search[]  = sprintf('~\[(%s)(?:=[^]]*)?]((?:(?!\[\1\b).)*?)\[/\1]\s*~si', 'list');
$search[]  = sprintf('~\[%s]~i', '\\*');
$replace[] = '$2';
$replace[] = '';
$count = 0;
do {
  $string = preg_replace($search, $replace, $string, -1, $count);
}
while ($count > 0);
return $string;

请参见PHP demo

我合并了前两个正则表达式,因为它们基本上匹配相同(open标记内的=.*?部分只是可选的,我建议使用(?:=[^]]*)?来匹配=然后匹配0+ ]以外的1或0次字符。

((?:(?!\[\1\b).)*?)模式是一个tempered greedy token模式,可确保最里面的list标签匹配,\1在这里与(%s)捕获的标签名称匹配

$count变量将保存用preg_replace完成的替换次数,如果不替换任何内容,则退出while块。