首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python 3-基于字符串的字典搜索列表

Python 3-基于字符串的字典搜索列表
EN

Stack Overflow用户
提问于 2016-12-07 05:06:26
回答 2查看 250关注 0票数 2

说我有绳子

代码语言:javascript
复制
"((attr1=25 and attr2=8) or attr3=15)"

代码语言:javascript
复制
"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"

代码语言:javascript
复制
"(attrXYZ=10)"

甚至是

代码语言:javascript
复制
"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"

以及包含字典的列表,其中每个字典都可能或不具有字符串中指定的属性。Python中是否有一种简单的方法来过滤与这种类型的字符串查询相匹配的字典?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-12-07 05:16:31

免责声明:这是一个非常懒惰和不安全的解决方案,它使用了Python、评估exec这两个最不光彩的函数,但如果输出与您提供的输出形状完全相同,则可以工作。

我们的策略是编辑输入,使其看起来类似Python自然理解的语法,而不是创建自己的解析器。为此,我们将使用dis模块(用于Python字节码的反汇编程序)来获取字符串中的所有名称。

代码语言:javascript
复制
import dis 

class Number:
    def __init__(self, n, exists=True):
        self.n = n
        self.exists = exists

    def __lt__(self, other):
        return self.n < other if self.exists else False

    def __le__(self, other):
        return self.n <= other if self.exists else False

    def __eq__(self, other):
        return self.n == other if self.exists else False

    def __ne__(self, other):
        return self.n != other if self.exists else False

    def __gt__(self, other):
        return self.n > other if self.exists else False

    def __ge__(self, other):
        return self.n >= other if self.exists else False


def clear_entries(entry):
    entry_output = entry.replace('!=', '<>').replace('=','==').replace('<>','!=')
    return entry_output

def check_condition(dict_, str_):
    str_ = clear_entries(str_)

    for k, v in dict_.items():
        exec("{0} = {1}".format(k, v))

    all_names = dis.Bytecode(str_).codeobj.co_names
    l_ = locals()
    non_defined_names = [v for v in all_names if v not in l_]

    for name in non_defined_names:
        exec("{0} = Number(0, exists=False)".format(name))  # the number value does not matter here (because of the 'exists' flag)

    if eval(str_):
        return True

    return False

测试

代码语言:javascript
复制
if __name__ == '__main__':
    entries = [
        "((attr1=25 and attr2=8) or attr3=15)",
        "((attr1>25 and attr2<50) or (attr3=10 and attr4=20))",
        "(2<attrXYZ<10)",
        "(attr1=20 and attr2=20 and attr3=20 and attr4=20)",
        "(attr1=20 or (attr2=20 and attr3=20 and attr4=20 and attr1231231=1))"
    ]

    dicts = [
        {'attr1': 25, 'attr2': 8, 'attr3': 123},
        {'attr1': 1, 'attr2': 8, 'attr3': 123},
        {'attr1': 26, 'attr2': 8, 'attr3': 123, 'attr4': 1},
        {'attr1': 1, 'attr2': 50, 'attr3': 1, 'attr4': 20},
        {'attr1': -1, 'attr2': 50, 'attr3': 1, 'attr4': 20},
        {'attrXYZ': 3},
        {'attrXYZ': 10},
        {'attr1': 20}

    ]

    for entry in entries:
        for d in dicts:
            print(check_condition(d, entry), '"{0}"'.format(entry), d)

结果

代码语言:javascript
复制
(True, '"((attr1=25 and attr2=8) or attr3=15)"', {'attr1': 25, 'attr2': 8, 'attr3': 123})
(False, '"((attr1=25 and attr2=8) or attr3=15)"', {'attr1': 1, 'attr2': 8, 'attr3': 123})
(False, '"((attr1=25 and attr2=8) or attr3=15)"', {'attr1': 26, 'attr2': 8, 'attr3': 123, 'attr4': 1})
(False, '"((attr1=25 and attr2=8) or attr3=15)"', {'attr1': 1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(False, '"((attr1=25 and attr2=8) or attr3=15)"', {'attr1': -1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(False, '"((attr1=25 and attr2=8) or attr3=15)"', {'attrXYZ': 3})
(False, '"((attr1=25 and attr2=8) or attr3=15)"', {'attrXYZ': 10})
(False, '"((attr1=25 and attr2=8) or attr3=15)"', {'attr1': 20})
(False, '"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"', {'attr1': 25, 'attr2': 8, 'attr3': 123})
(False, '"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"', {'attr1': 1, 'attr2': 8, 'attr3': 123})
(True, '"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"', {'attr1': 26, 'attr2': 8, 'attr3': 123, 'attr4': 1})
(False, '"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"', {'attr1': 1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(False, '"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"', {'attr1': -1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(False, '"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"', {'attrXYZ': 3})
(False, '"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"', {'attrXYZ': 10})
(False, '"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"', {'attr1': 20})
(False, '"(2<attrXYZ<10)"', {'attr1': 25, 'attr2': 8, 'attr3': 123})
(False, '"(2<attrXYZ<10)"', {'attr1': 1, 'attr2': 8, 'attr3': 123})
(False, '"(2<attrXYZ<10)"', {'attr1': 26, 'attr2': 8, 'attr3': 123, 'attr4': 1})
(False, '"(2<attrXYZ<10)"', {'attr1': 1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(False, '"(2<attrXYZ<10)"', {'attr1': -1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(True, '"(2<attrXYZ<10)"', {'attrXYZ': 3})
(False, '"(2<attrXYZ<10)"', {'attrXYZ': 10})
(False, '"(2<attrXYZ<10)"', {'attr1': 20})
(False, '"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"', {'attr1': 25, 'attr2': 8, 'attr3': 123})
(False, '"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"', {'attr1': 1, 'attr2': 8, 'attr3': 123})
(False, '"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"', {'attr1': 26, 'attr2': 8, 'attr3': 123, 'attr4': 1})
(False, '"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"', {'attr1': 1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(False, '"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"', {'attr1': -1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(False, '"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"', {'attrXYZ': 3})
(False, '"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"', {'attrXYZ': 10})
(False, '"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"', {'attr1': 20})
(False, '"(attr1=20 or (attr2=20 and attr3=20 and attr4=20 and attr1231231=1))"', {'attr1': 25, 'attr2': 8, 'attr3': 123})
(False, '"(attr1=20 or (attr2=20 and attr3=20 and attr4=20 and attr1231231=1))"', {'attr1': 1, 'attr2': 8, 'attr3': 123})
(False, '"(attr1=20 or (attr2=20 and attr3=20 and attr4=20 and attr1231231=1))"', {'attr1': 26, 'attr2': 8, 'attr3': 123, 'attr4': 1})
(False, '"(attr1=20 or (attr2=20 and attr3=20 and attr4=20 and attr1231231=1))"', {'attr1': 1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(False, '"(attr1=20 or (attr2=20 and attr3=20 and attr4=20 and attr1231231=1))"', {'attr1': -1, 'attr2': 50, 'attr3': 1, 'attr4': 20})
(False, '"(attr1=20 or (attr2=20 and attr3=20 and attr4=20 and attr1231231=1))"', {'attrXYZ': 3})
(False, '"(attr1=20 or (attr2=20 and attr3=20 and attr4=20 and attr1231231=1))"', {'attrXYZ': 10})
(True, '"(attr1=20 or (attr2=20 and attr3=20 and attr4=20 and attr1231231=1))"', {'attr1': 20})
票数 1
EN

Stack Overflow用户

发布于 2016-12-07 05:38:59

只有在确保查询字符串是安全的情况下,才能这样做。

(编辑:你真的应该使用像拟解析这样的东西,而不是做一些快速和肮脏的事情。)

如果源来自不受信任的输入,请执行而不是,在查询字符串上使用exec

代码语言:javascript
复制
import re

QUERY_EXEC_RE = re.compile('(\w+)=')

def _matches(query_exec, d):
    a = []
    exec('a.append({0})'.format(query_exec), globals(), locals())
    return a[0]

def query_dicts(query, dicts):
    query_exec = QUERY_EXEC_RE.sub(r'd.get("\1") == ', query)
    return [d for d in dicts if _matches(query_exec, d)]

示例:

代码语言:javascript
复制
query = "((attr1=25 and attr2=8) or attr3=15)"
dicts = [
    dict(attr1=1, attr2=2, attr3=3),
    dict(attr1=25, attr2=7, attr3=12),
    dict(attr1=24, attr2=8, attr3=13),
    dict(attr1=25, attr2=8, attr3=14),
    dict(attr1=5, attr2=1, attr3=15),
    dict(attr3=15),
    dict(attr1=25, attr2=8),
]
answer = query_dicts(query, dicts)
print(answer)

[{'attr1': 25, 'attr2': 8, 'attr3': 14},
 {'attr1': 5, 'attr2': 1, 'attr3': 15},
 {'attr3': 15},
 {'attr1': 25, 'attr2': 8}]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41009811

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档