我正在尝试改进可处理字符串中的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
标签,如果它们在列表中?
答案 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
块。