我正在使用PyParsing编写一个查询语言解析器,而且我已经陷入了(我相信是)一个前瞻问题.查询中的一个子句类型旨在将字符串拆分为3个部分(fieldname,operator,value),使得fieldname是一个单词,operator是一个或多个单词,value是单词,带引号的字符串或带括号的列表这些.
我的数据看起来像
author is william
author is 'william shakespeare'
author is not shakespeare
author is in (william,'the bard',shakespeare)
Run Code Online (Sandbox Code Playgroud)
我对此子句的当前解析器编写为:
fieldname = Word(alphas)
operator = OneOrMore(Word(alphas))
single_value = Word(alphas) ^ QuotedString(quoteChar="'")
list_value = Literal("(") + Group(delimitedList(single_value)) + Literal(")")
value = single_value ^ list_value
clause = fieldname + originalTextFor(operator) + value
Run Code Online (Sandbox Code Playgroud)
显然这会失败,因为operator
元素是贪婪的,并且value
如果它可以吞噬它.从阅读其他类似的问题和文档,我已经收集到我需要用一个NotAny
或那个来管理这个前瞻FollowedBy
,但是我还没有弄清楚如何使这个工作.
Pau*_*McG 12
这是Be Parser的好地方.或者更准确地说,让解析器像你一样思考.问问自己,"在'作者是莎士比亚'中,我怎么知道'莎士比亚'不是运营商的一部分?" 你知道'莎士比亚'是值,因为它在查询结束时,之后就没有了.因此,运算符单词不仅仅是alphas的单词,它们是alphas的单词,后面跟不是字符串的结尾.现在将前瞻逻辑构建到您的定义中operator
:
operator = OneOrMore(Word(alphas) + ~FollowedBy(StringEnd()))
Run Code Online (Sandbox Code Playgroud)
我认为这将开始更好地为您解析.
其他一些提示:
我只使用'^'运算符,如果有一些可能的歧义,就像我要解析一个数字可能是整数或十六进制的字符串.如果我使用Word(nums) | Word(hexnums)
,那么我可能会错误地处理"123ABC"只是领先的"123".通过改变'|' 到'^',将测试所有替代方案,并选择最长的匹配.在我解析十进制或十六进制整数的例子中,我可以通过反转替代方法获得相同的结果,并Word(hexnums)
首先进行测试.在您的查询语言中,没有办法将带引号的字符串与非引用的单个字值混淆(一个引用'
或者"
,另一个不引用),因此没有理由使用'^','|' 就足够了.类似的value = singleValue ^ listValue
.
将结果名称添加到查询字符串的关键组件将使以后更容易使用:
clause = fieldname("fieldname") + originalTextFor(operator)("operator") + value("value")
现在,您可以通过名称而不是解析位置来访问解析的值(一旦您开始使用可选字段等变得更加复杂,这将变得棘手和容易出错):
queryParts = clause.parseString('author is william')
print queryParts.fieldname
print queryParts.operator
归档时间: |
|
查看次数: |
2452 次 |
最近记录: |