无法弄清楚这个正则表达式有什么问题

时间:2010-10-09 21:25:51

标签: php regex

正规新手在这里。我正在尝试修复的论坛软件有一个(损坏的)插件。它产生了以下正则表达式:

/(?:\s|^)\[(?:\:\)\]|;\)\])(?:\s|$)/m

...使用[:)]替换文本块中的[;)]preg_replace()的所有实例。但是,它不会替换[:)][;)]的实例。有什么想法吗?

编辑:有问题的插件是Emoticons,对于Vanilla来说。这是代码(删除了不相关的部分和电子邮件地址):

    // 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" /> ';
}
// 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" /> '; }

2 个答案:

答案 0 :(得分:1)

这个(简化的)正则表达式应该替换[:)]和[;)]的每个实例:

(?:\[[:;]\)\])

答案 1 :(得分:0)

盲目猜测,因为没有代码和一些测试用例我无法确定:

该正则表达式仅捕获[:)][;)]的实例,这些实例被空格包围,或者位于字符串的开头或结尾。这就是(?:\s|^)(?:\s|$)的含义。它可能与设计不匹配Hello[:)]World。这是你正在测试它的情况吗?

编辑:知道了。由于正则表达式的编写方式,通过测试任一侧的空格,它包括匹配中的那些空格。那些比赛不能重叠。如果你要用两个空格分隔它们,你会看到预期的行为。

如果你不关心它没有反对言语,你的正则表达式的工作极其简化:逃避表情符号,然后用|加入它们,以产生/\[\:\)\]|\[\;\)\]/

这可能是一次使用str_replace几次的好地方。