-->

Convert BBCode [IMG] to

2019-07-13 20:36发布

问题:

I'm using preg_replace to convert all BBCode to HTML but can't get img tags to work. Here is my code:

$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);

Right now it creates an image tag with the link in but adds ] to the start and end of the link so it doesn't display the image correctly.

EDIT:

This is cause by me converting links to anchor tags and it's conflicting within the [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);

回答1:

Several points to make:

  • Change your pattern delimiters from / to ~ so that you don't have to escape the / characters that exist inside your pattern.
  • Simply do not use capture groups on substrings that you don't intend to use. In your patterns, none of the unwanted substrings need to be parenthetically wrapped to maintain pattern logic.
  • The regex engine will only consider ] to be the end of a character class if a character class is opened. For this reason, I am not escaping any ] characters.
  • Because you aren't using any anchors (^ or $), the m pattern modifier is needless.
  • If you want case-insensitivity in your pattern, use the i pattern flag/modifier.
  • After removing all of the excess capture groups, you only need to use $1 in the replacement string.
  • After processing the bbcoded urls, do a final sweep for any urls that are not already converted to html elements. (*SKIP)(*FAIL) "disqualifies" these unwanted substrings.

Code: (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-z\d.-]+\.[a-z]{2,3}/\S*?)](.*?)\[/url]~i',
    '~\[url]((?:ht|f)tps?://[a-z\d.-]+\.[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)|\bhttps?://.+?(?=\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));

Output:

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>',
)