::: PHP.com.ua - учимся вместе. ::: ::: PHP.com.ua - учимся вместе. :::



 
   - Вакансия PHP-программист, Днепропетровск...
  - Проблема с передачей переменной в PHP ск...
  - Как хранить конфигурацию cms'ки?
  - Проблема с сортировкой массива
  - коллизии md5
  - Странный глюк функции date
  - Скроллинг в iframe


Главная
Новости
Статьи
Шпаргалки
Файлы
О проекте
Форум
Футболки


FREEhost.com.ua - купил хостинг 10 у.е. на Begun в подарок.

iName.com.ua - регистрация доменных имен и хороший хостинг.

Библиотека программиста - нужный вам исходник или документация по необходимому для вас языку программирования.

Designclub - Клуб дизайнеров Украины.

Регистрация доменов
Хостинг

 HowtoForge.ORG.UA - Это первый Украинский ресурс развития open source программного обеспечения


Путь: Статьи > Готовые решения

Готовые решения

Автор: - 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$replacepreg_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.
Контакты Design by webFaction Ukrainian PHP Group 2004-2005