|
 |
Путь: >
Готовые решения
Готовые решения
Автор: - Zest
Дата публикации - 26.09.2004
Просмотров: - 5199
Формула выделения текста или поиск как в Google
[b]Автор оригинала[/b] [url=http://webmastak.com/articles/2005/04/29/as-google-search/]Байзульдин Т.М.[/url]
[p]Мысли в слух...[/p]
Как правило, каждый автор сайта старается сделать дизайн сайта и его функциональность как можно уникальней. Это касается как коммерческих сайтов так и домашних страничек. Все направлено на то, чтоб привлечь внимание посетителя сайта не только тематикой, но и удобной навигацией в море информации.
Количество информации постоянно увеличивается, а желание посетителя тратить свое время и деньги на бесплодные поиски интересующей его информации уменьшаются с каждым неудачным результатом поиска и посещением очередной ненужной ссылки.
Наиболее красиво решили эту задачу авторы всемирно известного поисковика "google", где в выводе результатов поиска выделяются искомые ключевые слова. Что служит нескольким целям, с одной стороны показывает пользователю, что данная строка была включена в результат поиска именно потому, что найдено соответствие, а главное посетителю легче ориентироваться. Не тратя зря времени на анализ вывода, где же то, что я искал и почему выведено то, что мне не нужно.
Задача становится особенно актуальной если, например, вам необходимо произвести поиск в таблице, по нескольким столбцам одновременно, и результатом поиска будет соответственно все та же таблица. В такой ситуации будет гораздо удобней просматривать уже заранее выделенный текст, а не высматривать его самостоятельно в каждой колонке.
Эта статья и описывает то, как написать свою функцию выделения найденного - искомого текста. И не просто выделить найденный текст цветом, а заключить его в определенные теги. Т.е. самим решать, что именно с ним делать. Выделить слово или его часть цветом, жирным шрифтом или подчеркнутым и т.д. Это уже зависит от фантазии разработчика.
[p]Итак сам код:[/p]
Воспользуемся мощнейшим инструментом поиска и замены - регулярными выражениями.
Создаем два массива: $search - что ищем и $replace - на что заменяем.
[php]
$searchquery - ключи поиска, разделенные пробелами.
$search = array(
"/\\\\\\\\/", // -- 1
"/([\r\n])[\s]+/", // -- 2
"/\s*(.+)\s*/", // -- 3
);
$replace = array(
"\\", // -- 1
" ", // -- 2
"\$1", // -- 3
);
[
/php]
[nb]Детальное описание работы с регулярными выражениями в PHP выходит за рамки этой статьи. Поэтому ограничусь описанием самой идеи того, как будет генерироваться регулярное выражение из строки запроса пользователя, в поле поиска.[/nb]
Итак каким целям служит каждый шаблон:
[ul]
[li] Заменяем повторяющиеся backslash'и (\) на один экранированный (\\). [/li]
[nb]Предполагается что magic_quotes=1 в php.ini или к строке запроса была применена функция addslashes($searchquery) если magic_quotes=0.[/nb][/li]
[li] Заменяем повторяющиеся пробелы, символы табуляции и перевода строки одним пробелом.[/li]
[li] Вырезаем результат двух предыдущих замен, отбрасываем пробелы в начале и конце строки, если они присутствуют конечно.
[php]
$sorted_regexp=preg_replace($search, $replace, preg_quote($searchquery));[
/php]
[/li][/ul]
В общем уже можно было бы и использовать полученный результат заменяя повторяющиеся пробельные символы не одним пробелом " ", а "|" тем самым получив готовое регулярное выражения сформированное из ключей поиска. Если бы не факты незаметные на первый взгляд.
А именно: никто не мешает пользователю ввести несколько идентичных ключей поиска, и зачем их "таскать" за собой или запрещать вводить? Но это не главное, главное то, что сгенерированное регулярное выражение и соответственно выделение текста, работать-то будет, но не так как ожидается. Дело в том, что при таком методе генерации регулярного выражения (шаблона для поиска и выделения) есть существенный недостаток состоящий в том, что поиск и выделение по такому шаблону зависит от того в каком порядке расположены и какой длины ключевые слова поиска.
Например, если посетителю или администратору сайта захочется произвести поиск по email'ам то при вводе запроса в следующей последовательности "@ @list.ru" (предположим, что искомые ключи находятся в таблице), то будут выделены все символы @, но при этом не выделится list.ru. Так как одиночный символ @ стоит первым то и в регулярном выражении он также окажется первым и при обработке текста удовлетворит условию поиска до "@list.ru".
Устраним описанный выше недостаток предприняв, затем, следующие действия:
[ul][li]Удалим дублирующиеся ключи поиска (если они есть).[/li]
[li]Отсортируем ключи поиска в порядке убывания - что и исправит недочет.[/li][/ul]
В дальнейшем понадобится отсортировать значения массива по их длине в порядке убывания.
Следующая функция поможет в этом:
[php]
<?
// === Сортировка значений массива по длине в порядке убывания.
// === используется совместно с usort
function sort_by_length ($cur_val, $next_val) {
$cur=strlen($cur_val);
$next=strlen($next_val);
if ($cur==$next) return 0;
return ($cur<$next)?-1:1;
}
// === Массив в который занесем ключи поиска - для дальнейшей сортировки
$sorted_regexp_array=array();
//Переменная $sorted_regexp - содержит результат работы preg_replace (см. выше).
// === Заносим ключи поиска в массив $sorted_regexp_array
$sorted_regexp_array=preg_split("/\s+/", $sorted_regexp);
// === Удаляем дублирующиеся значения в массиве
$sorted_regexp_array=array_unique($sorted_regexp_array);
// === Сортируем массив $sorted_regexp_array в порядке убывания
// === функция rev_sort_by_length - приведена выше.
usort($sorted_regexp_array, "rev_sort_by_length");
// === Объединяем отсортированные значения массива в строку.
$searchquery_regexp=implode("|", $sorted_regexp_array);
// === Заключаем результат в круглые скобки - группируем наш REGEXP
$searchquery_regexp=preg_replace("/.+/","(\$0)", $searchquery_regexp);
?>
[
/php]
Таким образом если переменная $searchquery содержала строку "@ @list.ru", то после выполнения описанных выше действий $searchquery_regexp будет содержать строку следующего вида "(@list\.ru|@)".
Сгенерированное регулярное выражение содержащееся в $searchquery_regexp готово к дальнейшему использованию. Например следующим образом:
[php]
$string_to_output=preg_replace(!$searchquery_regexp!i, "<SPAN STYLE='background-color: #FFFF00;'>\$0</SPAN>", $string_where_search);[
/php]
[nb]Обратите внимание на то что шаблон поиска заключен не в /, а в ! - иначе будет выдано сообщение об ошибке.[/nb]
Все, если в переменной $string_where_search содержащей строку будет найдено соответствие одному из ключей поиска - участок строки или слова будет заключен (в данном случае) в тег иначе строка останется без изменений.
Если используем шаблоны (Smatry Templates):
[php]
<?
{$string_where_search|regex_replace:"!$searchquery_regexp!i":"<SPAN STYLE='background-color: #FFFF00;'>\$0</SPAN>"}
?>[
/php]
Таким образом, при поиске в таблице по нескольким столбцам, можно назначить каждому столбцу свой стиль (цвет) выделения. Например: все найденные соответствия поиску в первой колонке выделять жирным шрифтом, а все соответствия во второй колонке синим цветом и т.д. Хоть по времени суток менять цвет или шрифт найденных значений.
[nb][b]ЗАМЕЧАНИЕ:[/b]
Выделение является языкозависимым. Т.е. если в строке поиска будет введен символ "a" в русской раскладке то выделены будут только русские символы "a". И соответственно если строка поиска введена в английской раскладке выделены будут только английские символы. Этим можно воспользоваться там где необходимо многоязыковое выделение.
Также при поиске в русскоязычном тексте учитывается регистр. Т.е. если в тексте есть "a" и "A" и ключом поиска был задан символ "a" (в русской раскладке), то будут выделены все "a", но не "A".
Т.е. поиск чувствителен к регистру не смотря на флаг i. Это замечание не относится к англоязычному тексту.[/nb]
Собираем все в функцию:
[php]
<?
function sort_by_length ($cur_val, $next_val) {
$cur=strlen($cur_val);
$next=strlen($next_val);
if ($cur==$next) return 0;
return ($cur<$next)?-1:1;
}
function generate_regexp_from_query ($searchquery, $search="", $replace="") {
$search = trim($search);
$replace = trim($replace);
if (empty($search) || empty($replace)) {
$search = array(
"/\\\\\\\\/",
"/([\r\n])[\s]+/",
"/\s*(.+)\s*/",
);
$replace = array(
"\\",
" ",
"\$1",
);
}
$sorted_regexp = preg_replace($search, $replace, preg_quote($searchquery));
$sorted_regexp_array = array();
$sorted_regexp_array = preg_split("/\s+/", $sorted_regexp);
$sorted_regexp_array = array_unique($sorted_regexp_array);
usort($sorted_regexp_array, "rev_sort_by_length");
$searchquery_regexp = implode("|", $sorted_regexp_array);
$searchquery_regexp = preg_replace("/.+/","(\$0)", $searchquery_regexp);
return $searchquery_regexp;
}
?>[
/php]
[p]Заключение:[/p]
Описанный пример выделения текста является более гибким инструментом выделения, чем встроенная функция highlight_string в которой нет свободы выбора. Что само по себе неприятно. Гораздо интересней, когда возможности ограничиваются только фантазией и не приходится каждый раз выдумывать велосипед. А тратить драгоценное время на творчество.
Обсудить в ФОРУМе - комментариев ()
Путь: >
Готовые решения
Если вы заметили орфографическую, стилистическую или другую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
|
|