Search code examples
phpsearchhighlighting

"like" search and highlighting in PHP


I have list of brands and want to provide a search function with highlighting. For example, there are the following brands

  • Apple
  • Cewe Color
  • L'Oréal
  • Microsoft
  • McDonald's
  • Tom Tailor

The user then types lor in search form. I'm using the following snippet for searching

class search {
  private function simplify($str) {
    return str_replace(array('&',' ',',','.','?','|','\'','"'), '', iconv('UTF-8', 'ASCII//TRANSLIT', $str));
  }
  public function do_search($search) {
    $search = self::simplify($search);
    $found = array();
    foreach (self::$_brands as $brand) {
      if (mb_strstr(self::simplify($brand['name']), $search) !== false) $found[]= $brand;
    }
    return $found;
  }
}

That gives me:

  • Cewe Color
  • L'Oréal
  • Tom Tailor

How would be a highlighting possible? Like:

  • Cewe Co<b>lor</b>
  • L'<b>Oré</b>al
  • Tom Tai<b>lor</b>

Btw: I know, that most things can be done with str_replace(), but that fit my needs not in all cases


Solution

  • self::$_brands contains result from database (containing columns name, name_lower, name_translit, name_simplified)

    class search {
        private function translit($str) {
            return iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', str_replace(array('ä', 'ü', 'ö', 'ß'), array('a', 'u', 'o', 's'), mb_strtolower($str)));
        }
    
        private function simplify($str) {
            return preg_replace('/([^a-z0-9])/ui', '', self::translit($str));
        }
    
        public function do_search($simplified) {
            $found = array();
            foreach (self::$_brands as $brand) {
                if (mb_strstr($brand['name_simplified'], $simplified) !== false) $found[]= $brand;
            }
            return $found;
        }
    
        private function actionDefault() {
            $search = $_POST['search_fld'];
            $simplified = self::simplify($search);
            $result = self::do_search($simplified);
            $brands = array();
            foreach ($result as $brand) {
                $hl_start = mb_strpos($brand['name_simplified'], $simplified);
                $hl_len = mb_strlen($simplified);
                $brand_len = mb_strlen($brand['name']);
                $tmp = '';
                $cnt_extra = 0;
                $start_tag = false;
                $end_tag = false;
                for ($i = 0; $i < $brand_len; $i++) {
                    if (($i - $cnt_extra) < mb_strlen($brand['name_simplified']) && mb_substr($brand['name_translit'], $i, 1) != mb_substr($brand['name_simplified'], $i - $cnt_extra, 1)) $cnt_extra++;
                    if (($i - $cnt_extra) == $hl_start && !$start_tag) {
                        $tmp .= '<b>';
                        $start_tag = true;
                    }
                    $tmp .= mb_substr($brand['name'], $i, 1);
                    if (($i - $cnt_extra + 1) == ($hl_start + $hl_len) && !$end_tag) {
                        $tmp .= '</b>';
                        $end_tag = true;
                    }
                }
                if ($start_tag && !$end_tag) $tmp .= '</b>';
                $brands[] = "<a href=\"/brand/" . rawurlencode($brand['name']) . "\">" . $tmp . "</a>";
            }
            echo implode(' | ', $brands);
        }
    }