<?php 
 
/*  
 * Copyright (c) 2009 Nguyen Duc Thuan <[email protected]> 
 * All rights reserved. 
 */ 
 
/** 
 * Text highlighter without affecting HTML tags. This class supports highlighting 
 * string in the double quotes of keyword for compatibility with some search methods such as 
 * MySQL Full-text search, Google, Yahoo... 
 * 
 * Sample usage: 
 * - Method 1: 
 *      $highlightedString = Fete_Util_Text_Highlighter::createInstance('<b>', '</b>')->highlight('PHP rules', 'rules'); 
 * - Method 2: 
 *      $highlighter = new Fete_Util_Text_Highlighter(); 
 *      $highlightedString = $highlighter->setBeforeMatch('<b>') 
 *                  ->setAfterMatch('</b>') 
 *                  ->highlight('PHP rules the world', '"PHP rules"'); 
 * 
 * @author Nguyen Duc Thuan <[email protected]> 
 */ 
class Fete_Util_Text_Highlighter 
{ 
    /** 
     * @var string 
     */ 
    protected $_beforeMatch = '<span style="background-color:yellow">'; 
 
    /** 
     * @var string 
     */ 
    protected $_afterMatch = '</span>'; 
 
    /** 
     * 
     * @param string $beforeMatch 
     * @param string $afterMatch 
     */ 
    public function __construct($beforeMatch = null, $afterMatch = null) 
    { 
        if (null !== $beforeMatch) { 
            $this->_beforeMatch = $beforeMatch; 
        } 
 
        if (null !== $afterMatch) { 
            $this->_afterMatch = $afterMatch; 
        } 
    } 
 
    /** 
     * 
     * @param string $beforeMatch 
     * @param string $afterMatch 
     * @return Fete_Util_Text_Highlighter 
     */ 
    static public function createInstance($beforeMatch = null, $afterMatch = null) 
    { 
        return new self($beforeMatch, $afterMatch); 
    } 
 
    /** 
     * 
     * @param string $beforeMatch 
     * @return Fete_Util_Text_Highlighter 
     */ 
    public function &setBeforeMatch($beforeMatch) 
    { 
        $this->_beforeMatch = $beforeMatch; 
        return $this; 
    } 
 
    /** 
     * 
     * @param string $afterMatch 
     * @return Fete_Util_Text_Highlighter 
     */ 
    public function &setAfterMatch($afterMatch) 
    { 
        $this->_afterMatch = $afterMatch; 
        return $this; 
    } 
 
    /** 
     * 
     * @param string $text 
     * @param string $keyword 
     * @return string highlighted string 
     */ 
    public function highlight($text, $keyword) 
    { 
        $output = ''; 
 
        $words = array(); 
 
        preg_match_all('#(?:"([^"]+)"|(?:[^\s\+\-"\(\)><~\*\'\|\\`\!@\#\$%^&_=\[\]\{\}:;,\./\?]+))#si', $keyword, $matches, PREG_SET_ORDER); 
 
        foreach ($matches as $match) 
        { 
            if (2 === count($match)) { 
                $words[] = $match[1]; 
            } else { 
                $words[] = $match[0]; 
            } 
        } 
 
        $words = implode('|', $words); 
 
        $textParts = preg_split('#(<script[^>]*>.*?</script>|<style[^>]*>.*?</style>|<.+?>)#si', $text, -1, PREG_SPLIT_DELIM_CAPTURE); 
 
        foreach ($textParts as $byHtmlPart) 
        { 
            if (!empty($byHtmlPart) && $byHtmlPart{0} != '<') { 
                $byHtmlPart = preg_replace('#(' . $words . ')#si', $this->_beforeMatch . '\1' . $this->_afterMatch, $byHtmlPart); 
            } 
 
            $output .= $byHtmlPart; 
        } 
 
        return $output; 
    } 
} 
 
 |