/** * * @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'>…</span>"; $fragment = strtr($fragment, array(" " => " ", "" => $open_tag, "" => $close_tag, ", " => " {$ellipsis} ", " " => $ellipsis, "," => $ellipsis, "" => $ellipsis)); // nc_search_util::restore_locale(); return $fragment; }