Регулярное выражение для пользовательского поиска

  • Автор темы Автор темы sanu0074
  • Дата начала Дата начала

sanu0074

Новичок
Сделал поиск в админке, добавил возможность пользователю искать совпадения в конкретных колонках таблицы с контентом, например он жмет на нужные кнопки и javascripto'm в строке поиска формируется подобное:
Код:
:name=первая && (:id>40 && :sect=content)
Рашифровка:
:name - это имя поля в таблице

&& и || - эквивалент AND и OR
скобки самособой понятно....

В итоге когда эта строка попадает на сервер, скрипт должен ее разбить и превратить в следующее,
будет строка такого вида:
Код:
name LIKE ? && (id> && sect LIKE ?)
И массив такого вида:
Код:
array('первая',40,'content')
Как это сделать? я голову ломаю, не могу составить регулярку кот все сделает. Тут следует понять, что данные могут меняться, скобок может не быть или быть несколько, знаки использую только >,<,= покачто других не придумал, знак "=" заменяем на "LIKE ?". Помогите решить задачку пожалуйста? И хочу видеть ваши замечания, насколько это тупо..) p.s. но хочу сделать именно так)
 
так не правильно делать
не надо писать новый промежуточный язык, это никому не нужно, сложно и для этих целей не ругярками надо пользоваться
 
Последнее редактирование:
Есть же готовые решения для полнотекстового поиска. Сфинкс тот же.
 
sanu0074, язык получился перегруженный. Например фраза `:name=` - это такая обязательная конструкция?
Какие варианты поиска бывают? Нужно их всех выписать и определить минимальный набор слов и знаков препинаний, чтобы можно было их отличать друг от друга.
Например:
Код:
:первая(:id>40 & :sect=content)
Это конструкция предписывает искать в столбце `первая` начиная с id>40 и искать `content`.
Условий можно вставить в строку сколько угодно.

Если я правильно понял условия, то фраза может выглядеть и так
Код:
:id(>40):первая(content | content2):вторая(>10&<60)
 
Если я правильно понял условия, то фраза может выглядеть и так
Код:
:id(>40):первая(content | content2):вторая(>10&<60)
нет, так не может, в таком случае, если я правильно понял, она например будет такая:
Код:
(:id>40) && (:первая=content || :первая=content2) && (:вторая>10 && :вторая<60)
 
sanu0074, Я предлагал более компактный вариант языка. Но это не особенно важно.
Нужно определить что будут искать. Нужно определиться какие названия столбцов будут. Что делать, если в данных для поиска или названиях есть символы &&, скобки и пробелы. В принципе - можно такие данные обрамлять кавычками. См С-шный квотинг или паскальное удвоение кавычек.
Получившийся результа будет довольно сложен для парсинга. Вообще говоря, не для одной регулярки.
Но сначала нужно зафиксировать входной язык. А для этого - придумать все возможные хотелки пользователя и попытаться вместить их в языковые конструкции.
 
ksnk, мне советовали лексер, в php он есть, но я не понял как его использовать в этом случае
 
Если так хочется делать машинный поиск, посмотри в сторону LDAP и его синтаксиса. Он намного лучше парсится и не так сложно читается.
 
вот код того что мне надо,
PHP:
$str = ':name=первая && (:id>40 && :sect=content)';
$param = array();

preg_match_all('/:([\w_]+)\s*([<>=]{1,2})\s*(["\'].*?["\']|[^\s()]+)/', $str, $out);
for($i=0; $i<count($out[0]); $i++){
    $key  = $out[1][$i];
    $sign = $out[2][$i];
    $val  = $out[3][$i];

    $str  = str_replace($out[0][$i], $key.(($sign == '=') ? ' LIKE' : $sign).' ?', $str);
    $param[] = $val;
}

echo $str;
print_r($param);
но немного не так работает, в результирующей строке:
Код:
name LIKE ? && (:id>40 && sect LIKE ?)
- здесь вместо ":id>40" - должно быть просто "id>" и в массиве $param всего два элемента, а должно быть три и вторым должен быть параметр "40".
Пробовал такую строку исходную -
Код:
:name=первая && :sect=abc
- работает
но если в строке уже есть знак > и число то все работает не так
Например при такой исходной строке
Код:
:name=первая && :sect>40
- результирующая выглядит так -
Код:
name LIKE ? && :sect>40
и массив так:
Код:
array(1) {
  [0]=>
  string(12) "первая"
}
т.е. такой же косячок что и с первоначальным вариантом.
Это единственное что осталось подправить, и покачто для той цели что мне надо - меня устроит...
 
Тебе нужен токенизатор, тут одним регэкспом на все случаи жизни не обойдёшься. (Верне, обойтись можно, но пользы от этого не будет - работать будет во столько же раз дольше, сколько альтернатив будет в регэкспе.)
 
Тебе нужен токенизатор, тут одним регэкспом на все случаи жизни не обойдёшься. (Верне, обойтись можно, но пользы от этого не будет - работать будет во столько же раз дольше, сколько альтернатив будет в регэкспе.)
насчет этого не сказал бы, работает во всех случаях, их тут несколько, единственный косяк в том что я выше выложил, тут беда со знаками > и < в регулярке. немогу решить досихпор
 
Код:
name LIKE ? && (id> ? && sect LIKE ?)Array
(
    [0] => первая
    [1] => 40
    [2] => content
)
Вот такой вывод дает скрипт. Что в нем неправильно?
 
Сверху