Pyparsing 空格和一些符号
Pyparsing whitespace and some symbols
我写了一个简单的解析器来解析带有 AND/OR/NOT 操作的简单语句。
import pyparsing
class ClauseExpression:
def __init__(self, tokens):
self.tokens = tokens
def __repr__(self):
return "field: {}, op: {}, value: {}".format(*self.tokens)
def asDict(self):
return self.tokens.asDict()
clause = (
pyparsing.oneOf("group tag").setResultsName("field")
+ pyparsing.Literal("=").setResultsName("op")
+ pyparsing.Word(pyparsing.alphanums).setResultsName("value")
).setParseAction(ClauseExpression)
class OpNode:
def __repr__(self):
return "{}:{!r}".format(self.op, self.items)
class UnOp(OpNode):
def __init__(self, tokens):
self.op = tokens[0][0]
self.items = [tokens[0][1]]
class BinOp(OpNode):
def __init__(self, tokens):
self.op = tokens[0][1]
self.items = tokens[0][::2]
statement = pyparsing.infixNotation(
clause,
[
(pyparsing.CaselessLiteral("NOT"), 1, pyparsing.opAssoc.RIGHT, UnOp),
(pyparsing.CaselessLiteral("AND"), 2, pyparsing.opAssoc.LEFT, BinOp),
(pyparsing.CaselessLiteral("OR"), 2, pyparsing.opAssoc.LEFT, BinOp),
],
)
def parse_result(result):
if isinstance(result, ClauseExpression):
return result.asDict()
elif isinstance(result, OpNode):
return {
"op": result.op,
"items": [parse_result(item) for item in result.items],
}
raise TypeError("Oh Noe! Something is not right.")
if __name__ == "__main__":
tests = (
"tag=TagA",
"tag=TagA AND tag=TagB",
"tag=TagA OR NOT tag=TagB",
)
for item in tests:
print("=" * 40)
print("INPUT:", item)
results = statement.parseString(item)
print("OUTPUT:", parse_result(results[0]))
print("=" * 40)
输出
========================================
INPUT: tag=TagA
OUTPUT: {'field': 'tag', 'op': '=', 'value': 'TagA'}
========================================
========================================
INPUT: tag=TagA AND tag=TagB
OUTPUT: {'op': 'AND', 'items': [{'field': 'tag', 'op': '=', 'value': 'TagA'}, {'field': 'tag', 'op': '=', 'value': 'TagB'}]}
========================================
========================================
INPUT: tag=TagA OR NOT tag=TagB
OUTPUT: {'op': 'OR', 'items': [{'field': 'tag', 'op': '=', 'value': 'TagA'}, {'op': 'NOT', 'items': [{'field': 'tag', 'op': '=', 'value': 'TagB'}]}]}
========================================
通过这些输出,我可以使用 Django Q 对象动态生成复杂的查找。
但是我不知道如何处理空格和符号(例如“&”)
对于输入 => tag=Tag C AND tag=E&F
输出 => {'field': 'tag', 'op': '=', 'value': 'Tag'}
我知道 pyparsing 默认忽略空格。
我需要以某种方式使用 pyparsing.White()
并排除 AND/OR/NOT 例如 pyparsing.NotAny(pyparsing.Or(['AND', 'OR', 'NOT']))
我是 pyparsing 的完全菜鸟,我们将不胜感激。
m1lton 的博客 post 非常适合您的专业形式。
使用 运行Tests 来 运行 你失败的测试字符串给出了这个:
tag=Tag C AND tag=E&F
^
FAIL: Expected end of text, found 'C' (at char 8), (line:1, col:9)
表示多词标签值没有被正确解析。
通常当人们允许在标签值等内容中使用空格时,他们会要求将它们括在引号中。通过使用否定前瞻,我们避免了这里的问题,但如果您添加更多关键字或运算符,您可能必须要求这样做。
查看此代码,了解我如何定义一个 tag_value 表达式,该表达式将接受多个单词而不会意外匹配您的任何关键字:
# define keywords to not be accepted as tag words
any_keyword = (pyparsing.Keyword("AND")
| pyparsing.Keyword("OR")
| pyparsing.Keyword("NOT"))
# define a tag word using lookahead to avoid keywords - also need to add "&" symbol
tag_word = ~any_keyword + pyparsing.Word(pyparsing.alphanums+"&")
# define a tag_value that can consist of multiple tag_words
# originalTextFor will return the original text used to match, including any whitespace
tag_value = pyparsing.originalTextFor(tag_word[1, ...])
那么 clause
就变成了:
clause = (
pyparsing.oneOf("group tag").setResultsName("field")
+ pyparsing.Literal("=").setResultsName("op")
+ tag_value.setResultsName("value")
).setParseAction(ClauseExpression)
给出这个测试输出:
tag=Tag C AND tag=E&F
[AND:[field: tag, op: =, value: Tag C, field: tag, op: =, value: E&F]]
我写了一个简单的解析器来解析带有 AND/OR/NOT 操作的简单语句。
import pyparsing
class ClauseExpression:
def __init__(self, tokens):
self.tokens = tokens
def __repr__(self):
return "field: {}, op: {}, value: {}".format(*self.tokens)
def asDict(self):
return self.tokens.asDict()
clause = (
pyparsing.oneOf("group tag").setResultsName("field")
+ pyparsing.Literal("=").setResultsName("op")
+ pyparsing.Word(pyparsing.alphanums).setResultsName("value")
).setParseAction(ClauseExpression)
class OpNode:
def __repr__(self):
return "{}:{!r}".format(self.op, self.items)
class UnOp(OpNode):
def __init__(self, tokens):
self.op = tokens[0][0]
self.items = [tokens[0][1]]
class BinOp(OpNode):
def __init__(self, tokens):
self.op = tokens[0][1]
self.items = tokens[0][::2]
statement = pyparsing.infixNotation(
clause,
[
(pyparsing.CaselessLiteral("NOT"), 1, pyparsing.opAssoc.RIGHT, UnOp),
(pyparsing.CaselessLiteral("AND"), 2, pyparsing.opAssoc.LEFT, BinOp),
(pyparsing.CaselessLiteral("OR"), 2, pyparsing.opAssoc.LEFT, BinOp),
],
)
def parse_result(result):
if isinstance(result, ClauseExpression):
return result.asDict()
elif isinstance(result, OpNode):
return {
"op": result.op,
"items": [parse_result(item) for item in result.items],
}
raise TypeError("Oh Noe! Something is not right.")
if __name__ == "__main__":
tests = (
"tag=TagA",
"tag=TagA AND tag=TagB",
"tag=TagA OR NOT tag=TagB",
)
for item in tests:
print("=" * 40)
print("INPUT:", item)
results = statement.parseString(item)
print("OUTPUT:", parse_result(results[0]))
print("=" * 40)
输出
========================================
INPUT: tag=TagA
OUTPUT: {'field': 'tag', 'op': '=', 'value': 'TagA'}
========================================
========================================
INPUT: tag=TagA AND tag=TagB
OUTPUT: {'op': 'AND', 'items': [{'field': 'tag', 'op': '=', 'value': 'TagA'}, {'field': 'tag', 'op': '=', 'value': 'TagB'}]}
========================================
========================================
INPUT: tag=TagA OR NOT tag=TagB
OUTPUT: {'op': 'OR', 'items': [{'field': 'tag', 'op': '=', 'value': 'TagA'}, {'op': 'NOT', 'items': [{'field': 'tag', 'op': '=', 'value': 'TagB'}]}]}
========================================
通过这些输出,我可以使用 Django Q 对象动态生成复杂的查找。
但是我不知道如何处理空格和符号(例如“&”)
对于输入 => tag=Tag C AND tag=E&F
输出 => {'field': 'tag', 'op': '=', 'value': 'Tag'}
我知道 pyparsing 默认忽略空格。
我需要以某种方式使用 pyparsing.White()
并排除 AND/OR/NOT 例如 pyparsing.NotAny(pyparsing.Or(['AND', 'OR', 'NOT']))
我是 pyparsing 的完全菜鸟,我们将不胜感激。
m1lton 的博客 post 非常适合您的专业形式。
使用 运行Tests 来 运行 你失败的测试字符串给出了这个:
tag=Tag C AND tag=E&F
^
FAIL: Expected end of text, found 'C' (at char 8), (line:1, col:9)
表示多词标签值没有被正确解析。
通常当人们允许在标签值等内容中使用空格时,他们会要求将它们括在引号中。通过使用否定前瞻,我们避免了这里的问题,但如果您添加更多关键字或运算符,您可能必须要求这样做。
查看此代码,了解我如何定义一个 tag_value 表达式,该表达式将接受多个单词而不会意外匹配您的任何关键字:
# define keywords to not be accepted as tag words
any_keyword = (pyparsing.Keyword("AND")
| pyparsing.Keyword("OR")
| pyparsing.Keyword("NOT"))
# define a tag word using lookahead to avoid keywords - also need to add "&" symbol
tag_word = ~any_keyword + pyparsing.Word(pyparsing.alphanums+"&")
# define a tag_value that can consist of multiple tag_words
# originalTextFor will return the original text used to match, including any whitespace
tag_value = pyparsing.originalTextFor(tag_word[1, ...])
那么 clause
就变成了:
clause = (
pyparsing.oneOf("group tag").setResultsName("field")
+ pyparsing.Literal("=").setResultsName("op")
+ tag_value.setResultsName("value")
).setParseAction(ClauseExpression)
给出这个测试输出:
tag=Tag C AND tag=E&F
[AND:[field: tag, op: =, value: Tag C, field: tag, op: =, value: E&F]]