Reputation: 23
Regex newbie here. There's a (broken) plugin for the forum software I use that I'm attempting to fix. It's generating the following regex:
/(?:\s|^)\[(?:\:\)\]|;\)\])(?:\s|$)/m
... to replace all instances of [:)]
or [;)]
in a block of text using preg_replace()
. However, it's not replacing the instances of [:)]
or [;)]
. Any ideas?
EDIT: The plugin in question is Emoticons, for Vanilla. Here's the code (irrelevant sections and e-mail addresses removed):
?>
// Build an Array containing the Emoticon<-->Graphic matches
if (!isset($EmoticonMatch))
{
$EmoticonMatch = array(
'[:)]' => 'smile.gif',
'[;)]' => 'wink.gif',
); // Add more matches, if you need them... Put the corresponding graphics into the Plugin's images-folder
}
// In case there's something wrong with the Array, exit the Function
if (count($EmoticonMatch) == 0)
return;
// Define the basic Regex pattern to find Emoticons
$EmoticonsSearch = '/(?:\s|^)';
// Automatically extend the Regex pattern based on the Emoticon-Codes in the $EmoticonMatch-Array
$subchar = '';
foreach ( (array) $EmoticonMatch as $Smiley => $Img ) {
$firstchar = substr($Smiley, 0, 1);
$rest = substr($Smiley, 1);
// new subpattern?
if ($firstchar != $subchar) {
if ($subchar != '') {
$EmoticonsSearch .= ')|(?:\s|^)';
}
$subchar = $firstchar;
$EmoticonsSearch .= preg_quote($firstchar, '/') . '(?:';
} else {
$EmoticonsSearch .= '|';
}
$EmoticonsSearch .= preg_quote($rest, '/');
}
// Add final Regex pattern to the Search-Variable
$EmoticonsSearch .= ')(?:\s|$)/m';
}
/**
* Hack the Discussion-Controller to replace Text with Smilies before output
*
* @since 1.0
* @version 1.0
* @author Oliver Raduner
*
* @uses Initialize()
* @uses FindEmoticon()
*/
public function DiscussionController_BeforeCommentDisplay_Handler(&$Sender)
{
// Get the current Discussion and Comments
$Discussion = &$Sender->EventArguments['Discussion'];
$Comment = &$Sender->EventArguments['Comment'];
// Initialize the our Emoticons-Stuff
$this->Initialize();
// Replace Emoticons in the Discussion and all Comments to it
$Discussion->Body = $this->FindEmoticon($Discussion->Body);
$Comment->Body = $this->FindEmoticon($Comment->Body);
}
/**
* Search through a Text and find any occurence of an Emoticon
*
* @since 1.0
* @version 1.0
* @author Oliver Raduner
*
* @uses $EmoticonImgTag()
* @global array $EmoticonsSearch()
* @param string $Text Content to convert Emoticons from.
* @return string Converted string with text emoticons replaced by <img>-tag.
*/
public function FindEmoticon($Text)
{
global $EmoticonsSearch;
$Output = '';
$Content = '';
// Check if the Emoticons-Searchstring has been set properly
if (!empty($EmoticonsSearch) )
{
$TextArr = preg_split("/(<.*>)/U", $Text, -1, PREG_SPLIT_DELIM_CAPTURE); // Capture the Tags as well as in between
$Stop = count($TextArr);
for ($i = 0; $i < $Stop; $i++)
{
$Content = $TextArr[$i];
// Check if it's not a HTML-Tag
if ((strlen($Content) > 0) && ('<' != $Content{0}))
{
// Documentation about preg_replace_callback: http://php.net/manual/en/function.preg-replace-callback.php
$Content = preg_replace_callback($EmoticonsSearch, array(&$this, 'EmoticonImgTag'), $Content);
}
$Output .= $Content;
}
} else {
// Return default text.
$Output = $Text;
}
return $Output;
}
/**
* Translate an Emoticon Code into a <img> HTML-tag
*
* @since 1.0
* @version 1.0
* @author Oliver Raduner
*
* @global array $EmoticonMatch
* @param string $Emoticon The Emoticon Code to convert to image.
* @return string HTML-Image-Tag string for the emoticon.
*/
public function EmoticonImgTag($Emoticon)
{
global $EmoticonMatch;
$PluginRoot = Gdn::Config('Garden.WebRoot'). 'plugins' . DS . 'Emoticons' . DS;
if (count($Emoticon) == 0) {
return '';
}
$Emoticon = trim(reset($Emoticon));
$Img = $EmoticonMatch[$Emoticon];
$EmoticonMasked = $Emoticon;
return ' <img src="'.$PluginRoot.'images'.DS.$Img.'" alt="'.$EmoticonMasked.'" class="emoticon" /> ';
}
Upvotes: 0
Views: 204
Reputation: 933
This (simplified) regular expression should replace every instance of [:)] and [;)] :
(?:\[[:;]\)\])
Upvotes: 1
Reputation: 85792
Blind guessing, since I can't know for sure without the code and some test cases:
That regular expression only catches instances of [:)]
and [;)]
that are either surrounded by whitespace, or are at the beginning or end of a string. That's what (?:\s|^)
and (?:\s|$)
mean. It will not match Hello[:)]World
, possibly by design. Is that the sort of case you're testing it on?
EDIT: Got it. Because of how the regular expression is written, by testing for spaces on either side, it includes those spaces in the match. Those matches can't overlap. If you were to separate them with two spaces, you would see intended behavior.
If you don't care about it not running up against words, your job with that regex is extremely simplified: escape the emoticons, then join them with |
, to produce /\[\:\)\]|\[\;\)\]/
.
This might be a better place to just use str_replace
a few times, though.
Upvotes: 0