Модераторы: skyboy, MoLeX, Aliance, ksnk
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> простой язык перечисления категорий 
:(
    Опции темы
ksnk
Дата 4.6.2015, 12:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



Преамбула:
В некоем магазине периодически-нерегулярно возникают разные акции для каких - то товаров. Примеры акции -
  •  купи товар X, тогда  на товар Y будет скидка Z
  •  купи товаров X на сумму Y и получи скидку Z
  •  ... и т.д. ограничено только фантазией маркетологов
У каждого товара есть категории (иногда - несколько). Акции включаются для всех товаров категории, за исключением таких-то подкатегорий. Список категорий тоже довольно активно изменяется - дополняется.

Сами эти акции, в общем, довольно сложно формализуемы (очень много разных правил, в админку выводить сильно лень),  и они кодятся прямо в отдельном классе, в PHP. 

Амбула:
Возникла проблема с компактным и легкопонимаемым способом указания списка категорий. Пока остановился на таком - строка с числами, в конце которых может быть знак + или -. 
Код

  if($item->checkCategories('501+ 128 172+ 201-')){
...
  };

В этой записи, товар ($item) проверяет, что его категория является подкатегорией 501 или 172 категории, либо точно совпадает с 128 и точно не является подкатегорией 201.
Парсинг такой строки выглядит тоже довольно компактно
Код

     if(preg_match_all('/(\d+)([\+\-])?/',$rules,$m))
        foreach($m[0] as $k=>$v){
            if($m[2][$k]=='-'){
                // - $m[1][$k] 
            } else if($m[2][$k]=='+'){
                // + $m[1][$k]
            } else {
                 //  $m[1][$k]
            }
        }
 

Пока возможностей, вроде хватает, но терзают сомнения, что логики в строковом представлении как-нибудь не хватит. Сталкивался ли  кто-нибудь с чем-то похожим? Возможно, с бОльшей логикой в записи?


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
baldina
Дата 4.6.2015, 17:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



такое не пройдет:
"категория товара не является подкатегорией категории С"
"скидка (не)предоставляется, если товар входит в категории A и B одновременно"

для реализации буйной фантазии нужны явные И, ИЛИ, НЕ и синтаксис, однозначно определяющий категорию и подкатегории.
PM MAIL   Вверх
ksnk
Дата 4.6.2015, 18:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



Цитата(baldina @  4.6.2015,  17:18 Найти цитируемый пост)
для реализации буйной фантазии нужны явные И, ИЛИ, НЕ и синтаксис, однозначно определяющий категорию и подкатегории. 


Ok. Предлагается такой синтаксис `[&|]?{категория}[+-.]?`.

Логика обработки правил сейчас такова, что по ИЛИ собираются все условия на "является категорией" или "является подкатегорией" и по И "не является подкатегорией". Тоесть, для каждого из первых 2-х условий "знак по уможчанию" - `|` - его можно опустить. Для "не является подкатегорией" - знак &. При желании - знак логической операции можно поменять.

`&501+ &172+` - знак & гарантирует, что товар находится и в подкатегории 501 и в 172.
Для полноты нужно бы порассуждать, может ли что-нибудь содержательное обозначать запись `|127-`... Вероятно, какая-то ненужная фигня...

Запись `127.` означает ИЛИ категория 127 И не подкатегория 127. Блин... что-то сложно.  smile 

В принципе - скобочную структуру можно заменить массивом правил. Правило подходит, если подходит хотя бы одно из его правил...



--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
baldina
Дата 4.6.2015, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



предлагается такой синтаксис: 
501* OR 128 OR 172* AND NOT 201

пример работы 
реализация
PM MAIL   Вверх
ksnk
Дата 5.6.2015, 00:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



FIQL - забавная штука, надо будет посмотреть 

Цитата(baldina @  4.6.2015,  23:21 Найти цитируемый пост)
501* OR 128 OR 172* AND NOT 201

Ok, вариант. Хотя, если смотреть на дерево синтаксиса - AND выполнится раньше, чем OR и получится логически не то, что мне надо. Без скобок, как надо,  записать не получится smile 




--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
baldina
Дата 5.6.2015, 01:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



Цитата(ksnk @  5.6.2015,  00:44 Найти цитируемый пост)
AND выполнится раньше, чем OR и получится логически не то, что мне надо

да, скобки нужны, сорри. dialekt поддерживает.
я скобки расставил бы просто за то, что c ними понятнее будет

Это сообщение отредактировал(а) baldina - 5.6.2015, 01:19
PM MAIL   Вверх
ksnk
Дата 9.6.2015, 11:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



Решил отряхнуть пыль с ушей и состряпать свой собственный парсер, с обратной польской записью и калькулятором...
Тынц

Синтаксис получившегося языка, примерно вот такой
128 or 512* and not 201*
или такой, он парсится в такую же конструкцию
128 512* not 201*

Основу составляет класс для компиляции в обратную польскую форму, которому для счастья нужно установить список операций с приоритетами, операции-суфиксы-унарные, и колбяки, которые и выполняют все эти операции.

Вот так, например, на нем выглядит калькулятор
Код

// just a simple number calculator
$r = new revpolnot_class();
$r->option(array(
//    'flags'=>12,
    'operation' => ['+' => 4, '-' => 4, '*' => 5, '/' => 5,],
    'suffix' => ['++' => 1],
    'unop' => ['-' => 1, '+' => 1],
    'tagreg' => '\b(\d+)\b',
    'evaluateTag' => function ($op) use ($r) {
            $r->log('eval:' . json_encode($op));
            if (!is_array($op) || !isset($op['data']))
                $result = $op;
            else {
                $result = 0 + $op['data']; // явное преобразование к числу
            }
            return $result;
        },
    'executeOp' => function ($op, $_1, $_2, $evaluate, $unop = false) use ($r) {
            $r->log('oper:' . json_encode($_1) . ' ' . $op . ' ' . json_encode($_2));
            if ($op == '+') {
                return call_user_func($evaluate, $_1) + call_user_func($evaluate, $_2);
            } else if ($op == '++') {
                return call_user_func($evaluate, $_2) + 1;
            } else if ($op == '-' && $unop) {
                return -call_user_func($evaluate, $_2);
            } else if ($op == '-') {
                return call_user_func($evaluate, $_1) - call_user_func($evaluate, $_2);
            } else if ($op == '*') {
                return call_user_func($evaluate, $_1) * call_user_func($evaluate, $_2);
            } else if ($op == '/') {
                return call_user_func($evaluate, $_1) / call_user_func($evaluate, $_2);
            } else {
                $r->error('unknown operation ' . $op);
            }
            return 0;
        }
));
foreach ([
             '(-3*-----4)*4++/5',
             '-1',
             '+1+1-1',
         ] as $k => $v) {
    echo "\n" . json_encode($r->ev($v, false));
    echo "\n" . $v . '=' . json_encode($r->ev($v));
    echo "\n";
}
 
Операция ++ здесь просто выдает значение на единицу больше.
Код

[{"data":"3"},{"op":"-","unop":true},{"op":"-","unop":true},{"op":"-","unop":true},
  {"op":"-","unop":true},{"op":"-","unop":true},{"data":"4"},{"op":"-","unop":true},
  {"op":"*"},{"data":"4"},{"op":"++","unop":true},{"op":"*"},{"data":"5"},{"op":"\/"}]
(-3*-----4)*4++/5=12

[{"data":"1"},{"op":"-","unop":true}]
-1=-1

[{"data":"1"},{"op":"+","unop":true},{"data":"1"},{"op":"+"},{"data":"1"},{"op":"-"}]
+1+1-1=1


Это сообщение отредактировал(а) ksnk - 9.6.2015, 11:35


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1500 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.