0

我正在尝试改进处理从字符串中清理 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]

是否可以仅使用 RegExp 去除[list][list=1]+[/list]标记以及[*]它们是否在列表中?

4

1 回答 1

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 演示

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

((?:(?!\[\1\b).)*?)模式是一个缓和的贪婪令牌,确保匹配最里面的list标签,\1这里匹配用 捕获的标签名称(%s)

$count变量将保存用 完成的替换次数preg_replace,如果没有替换,则while块退出。

于 2019-03-08T17:13:49.043 回答