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

标签 python string list dictionary filter

假设我有字符串

"((attr1=25 and attr2=8) or attr3=15)"

"((attr1>25 and attr2<50) or (attr3=10 and attr4=20))"

"(attrXYZ=10)"

甚至

"(attr1=20 and attr2=20 and attr3=20 and attr4=20)"

还有一个包含字典的列表,其中每个字典在字符串中可能有也可能没有指定的属性。在 Python 中有没有一种简单的方法来过滤匹配这种类型的字符串查询的字典?

最佳答案

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

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

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

测试

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)

结果

(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})

关于Python 3 - 基于字符串的字典搜索列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41009811/

相关文章:

javascript - 数字数组作为字符串到简单的 int 转换问题

string - Flutter 拆分并使特定单词加粗

C# 使用模式将两个字符串列表相交

python - 在另一个列表上应用 lambda 函数列表时的意外行为

python - 如何通过套接字和选择模块管理聊天服务器(Python)的套接字连接

python - Sphinx 文档,带编号的图形引用

python - 在 Python 中反转列表的顺序

python - 尝试在 Linux 服务器上运行 jupyter 笔记本

C++:带有空格的cin到没有getline函数的字符串

python - 加入列表由多个列表组成,这些列表在 python 中具有相同的值