| 
<?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;
 }
 }
 
 |