2015-08-26 5 views
0

У меня есть много больших коллекций объектов, которые необходимо фильтровать. Мне нужно, чтобы фильтры были гибкими и определяемыми пользователем.Фильтры, определяемые пользователем

Hard закодированы, это может выглядеть примерно так:

selected = set() 

for o in objects: 
    if o.someproperty == 'ab': 
     selected.add(o) 

    if o.a == 'a' and 'something' in o.b: 
     selected.add(o) 

Но мне нужно что-то я могу хранить в БД.

Я видел что-то, ссылающееся на это шаблон Criteria (или Filter) http://www.tutorialspoint.com/design_pattern/filter_pattern.htm, но я не могу найти много информации об этом.

Я хотел бы, чтобы правила были гибкими и сериализуемыми в простом формате.

Может быть выше, может выглядеть примерно так:

someproperty == 'ab' 
a == 'a', 'something' in b 

С каждой строкой правила является различным набором вещей, которые необходимо удовлетворить. Если какая-либо строка в наборе правил совпадает, объект включается. Но должна ли логическая логика быть наоборот (с and между линиями и or внутри них)? Оказывает ли это гибкость для обработки различных отрицаний? Как бы я его разобрал?

Какие простые подходы к этой проблеме?

Пару моего примера использует

# example 1 
for o in objects: 
    if o.width < 1 and o.height < 1: 
     selected.add(o) 

# example 2 
for o in objects: 

    if o.type == 'i' or o.type == 't': 
     continue 

    if not o.color: 
     selected.add(o) 
     continue 

    if o.color == 'ffffff': 
     selected.add(o) 
     continue 

    if o.color == '000000': 
     continue 

    grey = (o.color[1:3] == o.color[3:5] and o.color[1:3] == o.color[5:7]) 
    if grey: 
     selected.add(o) 
+0

ОЧЕНЬ простой способ - использовать 'eval', но делать это только в том случае, если вы хотите, чтобы ваш код ужасно нарушался. – muddyfish

+0

Это то, что я рассматриваю, но пока не слишком глубоко задумался. Я считаю, что вы можете контролировать контекст для 'eval'. –

+1

Вы можете сломать pythin даже с контролируемым 'eval' – muddyfish

ответ

1

Ну, если вы хотите метод безопасным вы не хотите хранить код в БД. Вы хотите, чтобы пользователь указал свойства, которые могут быть эффективно проанализированы и применены в качестве фильтра.

Я считаю, что бесполезно придумывать свой собственный язык для описания свойств. Просто используйте существующую. Например, XML (хотя я не поклонник ...). Фильтр может выглядеть следующим образом:

<filter name="something"> 
    <or> 
     <isEqual attrName="someproperty" type="str" value="ab" /> 
     <and> 
      <isEqual attrName="a" type="str" value="a" /> 
      <contains value="something" type="str" attribute="b" /> 
     </and> 
    </or> 
</filter> 

Вы можете разобрать XML, чтобы получить представление объекта фильтра. Из этого не должно быть трудно получить фрагмент кода, который выполняет действия.

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

Таким образом, фильтр легко модифицируется любым, кто имеет небольшое знание XML. Кроме того, вы можете расширить свою логику, и вам не нужно менять парсер для каждой новой конструкции, которую вы разрешаете.

+0

Спасибо за ваш ответ. Я предполагаю, что наличие дерева даст мне возможность вложить «и»/«или», но мне нужно. Может ли такое упрощение упростить до '(a ∨ b) ∧ (c ∨ d)' или '(a ∧ b) ∨ (c ∧ d)'? Это позволило бы мне сосредоточиться на части оператора равенства и т. Д. –

+0

@AidanKane Я не совсем понимаю ваш вопрос. Конечно, поскольку это просто логические формулы, вы можете преобразовать их в конъюнктивные или дизъюнктивные нормальные формы, есть алгоритмы для этого (один из двух должен быть эффективно генерируемым ...). Когда вы будете иметь их в нормальной форме, вы можете просто использовать списки вместо определенных классов «AndFilter» и «OrFilter». Например, вы можете представить '(a ∨ b) ∧ (c ∨ d)' as '[[a, b], [c, d]]', где самый внешний список - 'и', а внутренние списки - 'или (или наоборот). – Bakuriu

+0

Вот что я думал, да. В моем случае я думаю, что '(a ∧ b) ∨ (c ∧ d)' проще рассуждать - просто интересно, насколько оно «менее мощно». –