...

View Full Version : problem with preg_replace()



qhiiyr
03-04-2008, 03:57 AM
Hello, I have a problem using preg_replace for my bbcode. I want it to search for a color (i.e. "Red", "Blue", etc.) in the URL it is turning into a link, and then make that link that color.

The bbcode links are formed like usual: [ url=http://mysite.com/]text[/url]

The problem occurs when I have two links, like this:


[ url=http://mysite.com/Red/page.php]Link 1[/url] blah blah blah [ url=http://mysite2.com/Green/page2.php]Link 2[/url]

What happens is that PHP thinks that everything from the first http to the end of the second URL is all one URL. To help explain:

[ url=http://mysite.com/Red/page.php]Link 1[/url] blah blah blah [ url=http://mysite2.com/Green/page2.php]Link 2[/url]

It thinks that all the orange in there is all one URL, so it makes one link with the href attribute being that entire orange blob of text.

My preg_replace code for that part is this:



function parse($string) {
global $allcolors; // contains all colors to match (Red, Blue, Green, etc.)
foreach($allcolors as $color) {
// colors links accordingly if they have one of our colors in their url
$preg_find[] = '/\[url\=(.*?)' . $color . '(.*?)\](.*?)\[\/url\]/is';
$preg_replace[] = '<a href="$1' . $color . '$2" style="color: ' . $color . ';">$3</a>';
// ... some more code for bbcode ...
$string = preg_replace($preg_find, $preg_replace, $string);
return $string;


I can't figure out how to avoid it! Any help or suggestions are appreciated much. Thanks!

Fou-Lu
03-04-2008, 05:50 AM
It works otherwise right? I reaaalllly don't want to do any pattern matching right now -_-.
Anyway, what you are experiencing is PHP's greedyness. Simple fix, on your pattern modifiers (ie: '/^a.../si' the 'si' are your modifiers), add a 'U' to tell PHP to not be greedy. By default, it will seek anything between the two possible options you are giving it, including more calls. Try that, see if that fixes if for you.

qhiiyr
03-04-2008, 06:16 AM
Just tried it, same exact thing happens.

It works fine when there is only one link. It also works fine when I comment out the color-related code and let the link be parsed as a normal link (the normal link code was not shown in my first post).

Out of curiosity I added the U to the normal link parsing, and commented out the color-related parsing to see what would happen, and it actually seemed like it did the opposite of the desired effect -- the same problem I initially had occurs (it thinks the URL is that huge blob of text), only with the normal link parsing and not the color parsing.

I'm not too familiar with the modifiers; is there a modifier that does the opposite of whatever U does? It seems like that might help.

Fou-Lu
03-04-2008, 05:30 PM
What I can tell you (after testing it), is its not a greedyness thing:


function parse($string)
{
$allcolors = array('Red', 'Green');
foreach($allcolors as $color) {
// colors links accordingly if they have one of our colors in their url
$preg_find[] = '/\(.*?)\[\/url\]/is';
$preg_replace[] = '<a href="$1' . $color . '$2" style="color: ' . $color . ';">$3</a>';
// ... some more code for bbcode ...
}
$string = preg_replace($preg_find, $preg_replace, $string);
return $string;
}

$str = "Link 1 (http://mysite.com/Red/page.php) blah blah blah Link 2 (http://mysite2.com/Green/page2.php)";

echo parse($str);

This results in this:
[u]Link 1 blah blah blah Link 2
Where link 1 goes to: http://myslite.com/Red/page.php and http://mysite2.com/Green/page2.php.
So this block of code itself is alright. I'm thinking the problem in this case is it is interfering with the already existing url tag built into the system. If this is the case, you can probably get around modifying it by placing this as a higher priority in replacement than the url tag. If that still doesn't work, you will need to change the url code to reflect the possibility of a colour addition.

Try those out, see if either of them fix the problem for you.

qhiiyr
03-04-2008, 05:56 PM
Okay, after some testing I've figured out what the problem is, but I don't know how to fix it.

The code block you gave me only works when the colors in the array are in the same order as the links in the string. So if you change the array from
$allcolors = array('Red', 'Green'); to
$allcolors = array('Green', 'Red'); it doesn't work anymore.

Inigoesdr
03-04-2008, 08:21 PM
Here, try this:

function parse($string)
{
$allcolors = array('Red', 'Green', 'Black'); // this is set elsewhere, apparently
$allcolors = !empty($allcolors) ? implode('|', $allcolors) : 'Red'; // make sure allcolors always has a value
$replace = array('~\(.*?)\[/url\]~si' => '<a href="\\1\\2\\3" style="color: \\2;">\\4</a>');
$string = preg_replace(array_keys($replace), array_values($replace), $string);
return $string;
}

$str = "[url=http://mysite.com/Red/page.php]Link 1 ((https?://.*?/)(' . $allcolors . ')(/.*?)\) blah blah blah Link 2 (http://mysite2.com/Green/page2.php) blah blah blah Link 3 (http://mysite2.com/Black/page2.php)";

echo parse($str);
I changed the delimiter to a tilde to avoid having to escape all of the forwardslashes.

If you're only doing the color replace on the string you don't really need a function(or array of the replacements), unless you're replacing the same thing in multiple strings. If it's just one you can do something like this:

$str = "Link 1 (http://mysite.com/Red/page.php) blah blah blah Link 2 (http://mysite2.com/Green/page2.php) blah blah blah Link 3 (http://mysite2.com/Black/page2.php)";
$allcolors = array('Red', 'Green', 'Black'); // this is optional, and set elsewhere, apparently
$allcolors = !empty($allcolors) ? implode('|', $allcolors) : 'Red'; // make sure allcolors always has a value
$string = preg_replace('~\[url=(https?://.*?/)(' . $allcolors . ')(/.*?)\](.*?)\[/url\]~si', '<a href="\\1\\2\\3" style="color: \\2;">\\4</a>', $str);
echo $string;

qhiiyr
03-05-2008, 01:50 AM
Awesome! Had to change it a little, but it works perfect! Thanks a bunch!

Oh, and I actually did need to use it in a function, because I have a big parse function for parsing all text that needs to, well, be parsed, and this was only a small piece of it.

Thanks so much again!



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum