<?php
/*
* Copyright (c) 2009 Nguyen Duc Thuan <me@ndthuan.com>
* 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 <me@ndthuan.com>
*/
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;
}
}
|