Если нельзя, но очень хочется, то нужно обязательно и ничего в мире не стоит того, чтобы делать из этого проблему!


Интересна Java? Кликай по ссылке и изучай!
Если тебе полезно что-то из того, чем я делюсь в своем блоге - можешь поделиться своими деньгами со мной.
с пожеланием
столько времени читатели провели на блоге - 
сейчас онлайн - 

суббота, 6 марта 2010 г.

Мой первый лексический анализатор

Задача была такая. Есть странички Поиска чего-то там по каким-то критериям. Когда форма поиска заполнена и отправлена то возвращается список найденного. Тут все по классике. Клиент захотел, чтобы в заголовке странички с результатами поиска выводился какой-то текст не знаю какой, но зависящий от того, что было введено на форме поиска. Тоже, собственно, классика. Читаем дальше...

Ну хорошо. Первое решение было - создать на админке поле ввода, в котором указывать маску по типу:
Город ##city##. Поиск ##object_type##. В диапазоне цен от ##price_from## до ##price_to##.
а в скрипте динамически заменять ##bla_bla## на его значение.

Вот код, который это делает:
function replace_all_tags($string, $data) {
    $separator = '##';
    if (substr_count($string, $separator)) {
        foreach ($data as $key=>$value) {
            $string = str_replace($separator.$key.$separator, $value, $string);
        }
    }
    return $string;
}
На вход передаем строку шаблон и массив с данными (ХЗ как такой массив называется, но там данные хранятся под строковыми индексами - ассоциативный массив, что ли).

Все клево! Но, бывают случаи, когда форма заполняется таким образом, что некоторые параметры - пустые, а результирующий тайтл теряет смысл. В нашем примере, если поиск будет проводиться по области, а дпиапазон цен не указан, то в тайтле мы увидим
Город . Поиск квартир. В диапазоне цен от  до .
Не гуд! И тут на ум пришла идея сделать шаблоны более умными, а именно добавить оператор if.

Синтаксис его придумал такой {if (<условие>) <шаблон>}, где <условие> - имя параметра наличие (или отсутствие) которого проверяется, а <текст> - подшаблон, включающий в себя конструкции типа ##<имя переменной>## и/или текст. <условие> может быть с префиксом !, что означает - что мы проверяем отсутствие параметра, или без него (наличие параметра). К примеру в примере с городом и диапазоном цен, мы могли бы выкрутитсья так:
{if (city) Город ##city##.}{if (!city) Регион ##region##.} Поиск ##object_type##. {if (price_from) В диапазоне цен от ##price_from## до ##price_to##.}

А вот метод, которым стоит обработать шаблон, чтобы обработать все if конструкции.
function process_if_constructions($pattern, $parameters) {
    preg_match_all('"(\{if \((!?.+?)\) (.+?)\})"', $pattern, $if_constructions);
     
    foreach ($if_constructions[2] as $index=>$condition) {
        $invert = (strpos($condition, '!') === 0);
        if ($invert) {
            $name = substr($condition, 1);
        } else {
            $name = $condition; 
        }
        $parameter_present = (!!$parameters[$name]);
        if ($invert) {
            $parameter_present = !$parameter_present;
        }
      
        if ($parameter_present) {
            $replacement = $if_constructions[3][$index];
        } else {
            $replacement = '';
        }
        $pattern = str_replace($if_constructions[1][$index], $replacement, $pattern);
    }
    return $pattern;
}
На вход передается шаблон, и ассоциативный массив, а на выходе получаем шаблон содержащий только ##bla_bla## операторы.

Этот код можно было усложнять, но на данном этапе разработки мне хватило и этого.

Комментариев нет:

Отправить комментарий