我正在实现一个工具,可以让用户搜索文本中的术语。我目前专注于处理来自搜索的更复杂的输入。
我希望支持的运营商是:
此代码应该进入构建对数据库引擎的查询的Python后端,因此我需要一种方法来解析查询以转换适当的部分。是否有模块可以让我做到这一点?
我尝试查看 NLTK 的逻辑包,但它似乎做了太多的事情,而且我不清楚如何将其简化为这些功能。我想我需要像 NLTK 的语法树这样的东西,但我发现的只是添加语法标签的包,因此与语言模型相关联。
我会使用 PLY (Python Lex-Yacc) 或 SLY 来解析它。
(
PLY
和SLY
具有相同的作者,但PLY
使用函数而SLY
使用类)
我从
calc.py
中获取了示例 SLY
并创建了将查询转换为 的代码
^(abc & def) | xyz
到嵌套列表
['OR', ['NOT', ['AND', 'abc', 'def']], 'xyz']
应该很容易用来生成 SQL 查询
但是没有获取
" "
的功能。
我还没有尝试添加它。它可能需要更多更改,因为它可能以特殊方式使用空间。
其他例子:
(A&B)|(^C&D)
==>['OR', ['AND', 'A', 'B'], ['AND', ['NOT', 'C'], 'D']]
from sly import Lexer, Parser
class QueryLexer(Lexer):
tokens = { TEXT }
ignore = ' \t'
literals = { '&', '|', '^', '(', ')', }
# Tokens
TEXT = r'[a-zA-Z_][a-zA-Z0-9_]*'
@_(r'\n+')
def newline(self, t):
self.lineno += t.value.count('\n')
def error(self, t):
print("Illegal character '%s'" % t.value[0])
self.index += 1
class QueryParser(Parser):
tokens = QueryLexer.tokens
precedence = (
('left', '&', '|'),
('right', '^'),
)
def __init__(self):
self.names = { }
@_('expr')
def statement(self, p):
print(p.expr)
@_('expr "&" expr')
def expr(self, p):
return ['AND', p.expr0, p.expr1]
@_('expr "|" expr')
def expr(self, p):
return ['OR', p.expr0, p.expr1]
@_('"^" expr')
def expr(self, p):
return ['NOT', p.expr]
@_('"(" expr ")"')
def expr(self, p):
return p.expr
@_('TEXT')
def expr(self, p):
return p.TEXT
if __name__ == '__main__':
lexer = QueryLexer()
parser = QueryParser()
while True:
try:
text = input('query > ')
except EOFError:
break
if text:
parser.parse(lexer.tokenize(text))