Beispiel #1
0
 /**
  *
  * @param $text
  * @param $language
  * @param $max_num_words
  * @return string
  */
 protected function highlight($text, $language, $max_num_words)
 {
     if (!strlen(trim($text)) || !$this->query) {
         return $text;
     }
     // пусто, нечего делать
     // nc_search_util::set_utf_locale($language);
     $paragraphs = preg_split("/(?<!\\d)\\.(?!\\d)|(?:\\s*\r?\n\\s*){2,}/u", $text, -1, PREG_SPLIT_NO_EMPTY);
     $match_count = array();
     $regexp = $this->get_highlight_regexp($language);
     // на момент обработки используются спецсимволы:
     // \1 - начало совпадения
     // \2 - конец совпадения
     // \3 - пропуск (многоточие, ellipsis)
     //  $regexp = nc_search_util::convert($regexp, 1);
     foreach ($paragraphs as $n => $p) {
         $paragraphs[$n] = preg_replace($regexp, "\$1", $p, -1, $count);
         $match_count[$n] = $count;
     }
     // правила формирования:
     // - показывается фрагмент с наибольшим количеством совпадений
     // - если предыдущее предложение заканчивается на слово короче 3 букв
     //   (предположительно — сокращение, инициал), его следует «прилепить»
     //   к текущему;
     // - если совпадение дальше $max_num_words от начала, обрезать
     //   начало строки
     // - всего в фрагменте не более $max_num_words слов;
     // - если в фрагменте менее $max_num_words слов, попробовать прилепить
     //   следующий по количеству совпадений фрагмент (если есть), поставить
     //   между ними ellipsis
     arsort($match_count, SORT_NUMERIC);
     $n = nc_search_util::get_nth_key($match_count, 0);
     $fragment = $paragraphs[$n];
     $prev = $next = $n;
     $short_word_regexp = "/(?<![\\pL\\d])\\pL{1,2}\$/u";
     while (--$prev >= 0 && preg_match($short_word_regexp, $paragraphs[$prev])) {
         $fragment = $paragraphs[$prev] . ". " . $fragment;
     }
     while (isset($paragraphs[++$next]) && preg_match($short_word_regexp, $fragment)) {
         $fragment .= ". " . $paragraphs[$next];
     }
     // put a dot at the end
     $fragment .= ".";
     $num_words_in_fragment = preg_match_all("/[\\pL\\d]+/u", $fragment, $tmp);
     if ($num_words_in_fragment < $max_num_words - 5) {
         // максимум будет показано два фрагмента
         $another_n = nc_search_util::get_nth_key($match_count, 1);
         if ($another_n !== null) {
             $another_fragment = $this->cut_fragment($paragraphs[$another_n] . ".", $max_num_words - $num_words_in_fragment);
             $shift = $another_n - $n;
             if ($shift < -1) {
                 $fragment = "{$another_fragment}  {$fragment}";
             } elseif ($shift > 1) {
                 $fragment = "{$fragment}  {$another_fragment}";
             } elseif ($shift > 0) {
                 $fragment = "{$fragment} {$another_fragment}";
             } else {
                 $fragment = "{$another_fragment} {$fragment}";
             }
         }
     }
     $fragment = $this->cut_fragment($fragment, $max_num_words);
     if (nc_search::should('HighlightMatchedWords')) {
         $open_tag = "<strong class='matched'>";
         $close_tag = "</strong>";
     } else {
         $open_tag = "";
         $close_tag = "";
     }
     $ellipsis = "<span class='skipped'>&hellip;</span>";
     $fragment = strtr($fragment, array(" " => " ", "" => $open_tag, "" => $close_tag, ", " => " {$ellipsis} ", " " => $ellipsis, "," => $ellipsis, "" => $ellipsis));
     // nc_search_util::restore_locale();
     return $fragment;
 }