I'm looking to write a shortcode system for a gaming community/database, where users can add things like ((Magical Sword))
to their content, and it'll be parsed into a nice link to relevant item with an inline thumbnail image.
Here's the code I'm using so far:
function inlineItems($text) {
$re = "/\(\(([^)] )\)\)/m";
preg_match_all($re, $text, $matches, PREG_SET_ORDER, 0);
foreach($matches as $match) {
$slug = makeSlug($match[1]);
$item = getItem($slug);
if($item) {
$text = preg_replace($match[0], '<a data-tooltip="tooltip-item-' . $item->slug . '" href="/items/' . $item->slug .'"><img src="/images/items/' . $item->slug .'.png">' . $item->name .'</a>', $text);
}
}
$text = str_replace("((", "", $text);
$text = str_replace("))", "", $text);
return $text;
}
Example output, if a user entered ((Crystal Sword))
would be:
<a data-tooltip="tooltip-item-crystal-sword" href="/items/crystal-sword"><img src="/images/items/crystal-sword.png">Crystal Sword</a>
So far so good, everything works great.
However, an issue occurs when a particular match is repeated multiple times in one text string.
If a user enters something like: A ((Crystal Sword)) is essential for farming, get a ((Crystal Sword)) as soon as you can. ((Crystal Sword)) is the best!
then the replacement matches the item name multiple times, and ends up with a mess like this:
<a data-tooltip="tooltip-item-crystal-sword" href="/items/crystal-sword"><img src="/images/items/crystal-sword.png"></a><a data-tooltip="tooltip-item-crystal-sword" href="/items/crystal-sword"><img src="/images/items/crystal-sword.png"></a><a data-tooltip="tooltip-item-crystal-sword" href="/items/crystal-sword"><img src="/images/items/crystal-sword.png">Crystal Sword</a>
How do I prevent it from overlapping matches like this?
CodePudding user response:
Your code is pretty messy. You don't need all those replaces all around, one is enough. Follow the KISS principle:
<?php
function inlineItems($text) {
$re = "/\(\((. ?)\)\)/m";
return preg_replace_callback($re, function($matches){
$item = getItem( makeSlug($matches[1]) );
return "<a class='text-item' data-tooltip='tooltip-item-{$item->slug}' href='/items/{$item->slug}'>
<img src='images/items/{$item->slug}.png'>
{$item->name}
</a>";
}, $text);
}
print inlineItems('A ((Crystal Sword)) is essential for farming, get a ((Crystal Sword)) as soon as you can. ((Crystal Sword)) is the best!');