将BBCode[img]转换为<img>

2022-03-22 00:00:00 regex image php preg-replace bbcode

我正在使用PREG_REPLACE将所有BBCode转换为HTML,但无法使img标记工作。以下是我的代码:

$search = array (
    '/([b])(.*?)([/b])/m',
    '/([i])(.*?)([/i])/m',
    '/([u])(.*?)([/u])/m',
    '/([ul])(.*?)([/ul])/m',
    '/([li])(.*?)([/li])/m',
    '/([user=)(.*?)(])(.*?)([/user])/m',
    '/([url=)(.*?)(])(.*?)([/url])/m',
    '/([url])(.*?)([/url])/m',
    '/([img=)(.*?)(])(.*?)([/img])/m',
    '/([quote])(.*?)([/quote])/m',
    '/([code])(.*?)([/code])/m',
);

$replace = array (
    '<strong>$2</strong>',
    '<em>$2</em>',
    '<u>$2</u>',
    '<ul>$2</ul>',
    '<li>$2</li>',
    '<a href="../login/profile?u=$2" target="_blank">$2</a>',
    '<a href="$2" target="_blank">$4</a>',
    '<a href="$2" target="_blank">$2</a>',
    '<img src="$4"></img>',
    '<quote>$2</quote>',
    '<code>$2</code>'
);

$string = preg_replace($search, $replace, $string);

现在,它会创建一个包含链接的图像标记,但会将]添加到链接的开始和结束位置,因此它无法正确显示图像。

编辑:

这是因为我将链接转换为锚定标记,并且在[img]BBCode内冲突。

$url = '/(http|https|ftp|ftps)://[a-zA-Z0-9-.]+.[a-zA-Z]{2,3}(/S*)?/';

$string = preg_replace($url, '[url=$0]$0[/url]', $string);

解决方案

要说明的几点:

  • 将模式分隔符从/更改为~,这样您就不必转义存在于模式中的/字符。
  • 请不要在您不打算使用的子字符串上使用捕获组。在您的模式中,不需要对任何不需要的子字符串进行括号包装以维护模式逻辑。
  • 如果打开了字符类,正则表达式引擎只会将]视为字符类的末尾。因此,我不会转义任何]字符。
  • 因为您没有使用任何锚点(^$),所以不需要m模式修饰符。
  • 如果希望模式不区分大小写,请使用i模式标志/修饰符。
  • 删除所有多余的捕获组后,您只需在替换字符串中使用$1
  • 在处理bbcode URL之后,对任何尚未转换为html元素的URL进行最后一次扫描。(*SKIP)(*FAIL)"取消"这些不需要的子字符串的资格。

编码:(Demo)

$bbcodes = [
    'Look at this:https://www.example.com/example?ohyeah=sure#okay this is a raw link',
    'No attibute bbcode url: [url]http://example.com/x1[/url]',
    'A url with link and link text: [url=http://example.com/x2]x2[/url]',
    'Image with "ignorable" text: [IMG=sumpthing.jpg]sumpthing[/IMG]',
    'Image: [img=sumpinelse][/img]'
];

$search = array (
    // ...
    '~[url=((?:ht|f)tps?://[a-zd.-]+.[a-z]{2,3}/S*?)](.*?)[/url]~i',
    '~[url]((?:ht|f)tps?://[a-zd.-]+.[a-z]{2,3}/S*?)[/url]~i',
    // ...
    '~[img=(.*?)].*?[/img]~i',  // if you want the possibility of dot matching newlines, add s pattern modifier
    // ...
    '~(?:<a.*?</a>|<img.*?</img>)(*SKIP)(*FAIL)|https?://.+?(?=s|$)~im'  // mop up any remaining links that are not bbtagged
);
$replace = array (
    // ...
    '<a href="$1" target="_blank">$2</a>',
    '<a href="$1" target="_blank">$1</a>',
    // ...
    '<img src="$1"></img>',
    // ...
    '<a href="$0" target="_blank">$0</a>',
);
var_export(preg_replace($search, $replace, $bbcodes));

输出:

array (
  0 => 'Look at this:<a href="https://www.example.com/example?ohyeah=sure#okay" target="_blank">https://www.example.com/example?ohyeah=sure#okay</a> this is a raw link',
  1 => 'No attibute bbcode url: <a href="http://example.com/x1" target="_blank">http://example.com/x1</a>',
  2 => 'A url with link and link text: <a href="http://example.com/x2" target="_blank">x2</a>',
  3 => 'Image with "ignorable" text: <img src="sumpthing.jpg"></img>',
  4 => 'Image: <img src="sumpinelse"></img>',
)

相关文章