编辑:我保留了答案的第一部分,因为如果这不是学校作业,我认为这仍然是完成任务的更好方法。我将答案的第二部分替换为更新匹配 OP 的问题。
您似乎想要做的是创建一个查询字符串解析器,它将读取查询字符串并将其转换为一系列 AND/OR/NOT 组合以返回正确的键。
有两种方法。
- 根据您所写的内容,到目前为止,最简单的解决方案是将数据加载到任何 SQL 数据库(例如,SQLite,它不需要完整的运行 SQL 服务器),将字典键作为单独的字段加载(如果您不关心普通格式 &c,您的其余数据可能都在另一个字段中),并将传入的查询转换为 SQL,大致如下:
SQL表至少有这个:
CREATE TABLE my_data(
dictkey text,
data text);
python_query="foo OR bar AND NOT gazonk"
sql_keywords=["AND","NOT","OR"]
sql_query=[]
for word in python_query.split(" "):
if word in sql_keywords:
sql_query+=[ word ]
else:
sql_query+=["dictkey='%s'" % word]
real_sql_query=" ".join(sql_query)
这需要对 SQL 注入和特殊字符进行一些转义和控制检查,但通常它只会将您的查询转换为 SQL,当针对 SQL 数据库运行时,它将返回键(可能还有数据)以进行进一步处理。
- 现在是纯 Python 版本。
您需要做的是分析您获得的字符串并将逻辑应用于您现有的 Python 数据。
分析字符串以将其简化为特定组件(及其交互)是解析。如果您真的想构建自己的完全成熟的解析器,那么会有 Python 模块,但是,对于学校作业,我希望您的任务是构建自己的。
根据您的描述,查询可以用准BNF 形式表示为:
(<[NOT] word> <AND|OR>)...
既然你说优先级并不相关,你可以用简单的方法逐字解析。
然后,您必须将关键字与文件名匹配,正如另一个答案中提到的那样,使用sets最容易做到这一点。
因此,它可能大致是这样的:
import re
query="foo OR bar AND NOT gazonk"
result_set=set()
operation=None
for word in re.split(" +(AND|OR) +",query):
#word will be in ['foo', 'OR', 'bar', 'AND', 'NOT gazonk']
inverted=False # for "NOT word" operations
if word in ['AND','OR']:
operation=word
continue
if word.find('NOT ') == 0:
if operation is 'OR':
# generally "OR NOT" operation does not make sense, but if it does in your case, you
# should update this if() accordingly
continue
inverted=True
# the word is inverted!
realword=word[4:]
else:
realword=word
if operation is not None:
# now we need to match the key and the filenames it contains:
current_set=set(inverted_index[realword].keys())
if operation is 'AND':
if inverted is True:
result_set -= current_set
else:
result_set &= current_set
elif operation is 'OR':
result_set |= current_set
operation=None
print result_set
请注意,这不是一个完整的解决方案(例如,它不包括处理查询的第一项,并且它要求布尔运算符为大写),并且未经测试。但是,它的主要目的应该是向您展示如何去做。做更多的事情就是为你写课程作业,这对你不利。因为你应该学习如何去做,这样你才能理解它。随时要求澄清。