Python PyParsing-语法元素围绕其他元素拆分
我正在移动一个工具(不是我写的)来使用PyParsing。我正在更新语法以使其更有意义,但也希望向后兼容。语法包括被另一个元素分割的元素,我需要“动词”(包装元素)和“值”(包装元素)。(不,这些不是地球仪,尽管它们看起来很像——这让人困惑,这也是我改变它的部分原因) 我很难理解如何解析像Python PyParsing-语法元素围绕其他元素拆分,python,pyparsing,Python,Pyparsing,我正在移动一个工具(不是我写的)来使用PyParsing。我正在更新语法以使其更有意义,但也希望向后兼容。语法包括被另一个元素分割的元素,我需要“动词”(包装元素)和“值”(包装元素)。(不,这些不是地球仪,尽管它们看起来很像——这让人困惑,这也是我改变它的部分原因) 我很难理解如何解析像*thing*这样的东西,其中“动词”围绕着“值”。这些元素也在一个分隔列表中,尽管我对这一部分没意见 我将要分析的内容的完整示例: command *thing*, !*other_thing*, *thir
*thing*
这样的东西,其中“动词”围绕着“值”。这些元素也在一个分隔列表中,尽管我对这一部分没意见
我将要分析的内容的完整示例:
command *thing*, !*other_thing*, *third_thing
我所尝试的:
import pyparsing as pp
command = pp.Keyword("command").setResultsName("command")
value = pp.Word(pp.alphanums + "_").setResultsName("value", listAllMatches=True)
contains = ("*" + value + "*").setResultsName("verb", listAllMatches=True)
not_contains = ("!*" + value + "*").setResultsName("verb", listAllMatches=True)
starts_with = ("*" + value).setResultsName("verb", listAllMatches=True)
verbs_and_values = (
contains
| not_contains
| starts_with
)
directive = pp.Group(command + pp.delimitedList(verbs_and_values, delim=","))
example = "command *thing*, !*other_thing*, *third_thing"
result = directive.parseString(example)
print result.dump()
这将获取所有值,但动词是全部内容(即['*'、'thing'、'*']
)。我尝试用类似以下的动作调整动词:
def process_verb(tokens):
if tokens[0] == '*' and tokens[-1] == '*':
return "contains"
# handle other verbs...
这很好,但它会将值吹走…我发现您正在使用结果名称和
listalmatches=True
来捕获分隔列表中的多个解析值。这对于简单的数据结构来说是可以的,但是一旦您想要为给定的值存储多个值,那么您就需要开始使用Group或parse action类
一般来说,我避免在低级表达式上使用结果名称,而是在使用“+”和“|”运算符编写高级表达式时添加它们。我也主要使用expr(“name”)
表单而不是expr.setResultsName(“name”)
表单来设置结果名称
以下是使用组的代码的修改版本:
command = pp.Keyword("command")
value = pp.Word(pp.alphanums + "_")
contains = pp.Group("*" + value("value") + "*")
not_contains = pp.Group("!*" + value("value") + "*")
starts_with = pp.Group("*" + value("value"))
我还添加了命令的结果名称和指令中的动词列表
:
directive = pp.Group(command("command")
+ pp.Group(pp.delimitedList(verbs_and_values,
delim=","))("verbs"))
既然这些表达式已包装在组中,就不必使用listAllMatches=True
,因为每个值现在都保存在各自的组中
现在解析的结果如下所示:
[['command', ['*', 'thing', '*'], ['!*', 'other_thing', '*'], ['*', 'third_thing']]]
[0]:
['command', ['*', 'thing', '*'], ['!*', 'other_thing', '*'], ['*', 'third_thing']]
- command: 'command'
- verbs: [['*', 'thing', '*'], ['!*', 'other_thing', '*'], ['*', 'third_thing']]
[0]:
['*', 'thing', '*']
- value: 'thing'
[1]:
['!*', 'other_thing', '*']
- value: 'other_thing'
[2]:
['*', 'third_thing']
- value: 'third_thing'
使用解析操作添加有关动词类型的信息是正确的,但是您不想返回该值,而是希望将动词类型添加为另一个类型
命名结果
def add_type_parse_action(verb_type):
def pa(s, l, t):
t[0]["type"] = verb_type
return pa
contains.addParseAction(add_type_parse_action("contains"))
not_contains.addParseAction(add_type_parse_action("not_contains"))
starts_with.addParseAction(add_type_parse_action("starts_with"))
添加解析操作后,将得到以下结果:
[['command', ['*', 'thing', '*'], ['!*', 'other_thing', '*'], ['*', 'third_thing']]]
[0]:
['command', ['*', 'thing', '*'], ['!*', 'other_thing', '*'], ['*', 'third_thing']]
- command: 'command'
- verbs: [['*', 'thing', '*'], ['!*', 'other_thing', '*'], ['*', 'third_thing']]
[0]:
['*', 'thing', '*']
- type: 'contains'
- value: 'thing'
[1]:
['!*', 'other_thing', '*']
- type: 'not_contains'
- value: 'other_thing'
[2]:
['*', 'third_thing']
- type: 'starts_with'
- value: 'third_thing'
您还可以定义类来为结果提供结构。由于类被“调用”时就好像它是一个解析操作,Python将使用解析的标记构造一个类实例:
class VerbBase:
def __init__(self, tokens):
self.tokens = tokens[0]
@property
def value(self):
return self.tokens.value
def __repr__(self):
return "{}(value={!r})".format(type(self).__name__, self.value)
class Contains(VerbBase): pass
class NotContains(VerbBase): pass
class StartsWith(VerbBase): pass
contains.addParseAction(Contains)
not_contains.addParseAction(NotContains)
starts_with.addParseAction(StartsWith)
result = directive.parseString(example)
print(result.dump())
现在,结果是对象实例,其类型指示使用了哪种动词:
[['command', [Contains(value='thing'), NotContains(value='other_thing'), StartsWith(value='third_thing')]]]
[0]:
['command', [Contains(value='thing'), NotContains(value='other_thing'), StartsWith(value='third_thing')]]
- command: 'command'
- verbs: [Contains(value='thing'), NotContains(value='other_thing'), StartsWith(value='third_thing')]
注意:在整个问题中,您将命令后面的项目称为“动词”,我在这个答案中保留了这个名称,以便与您最初的尝试进行比较。但通常,“动词”指的是一些动作,比如指令中的“命令”,下面的项目更像是“限定符”或“参数”。在编码时,名字是很重要的,不仅仅是在与他人交流时,甚至是在形成自己对代码所做工作的心理概念时。对我来说,这里的“动词”,通常是句子中的动作,更像是命令,而下面的部分我称之为“限定词”、“参数”或“主语”。谢谢你给出了一个非常棒的答案!我不知道对结果进行分组会保留它们,并使listAllMatches变得不必要,这现在更有意义了。Re:动词,我想这实际上是我在MWE中命名不好的“命令”。“Is”和“contains”等是词性意义上的动词,但您的轻推让我再次看到了生产代码中的命名,而且肯定有更好的选择-因为这是访问ORM,我将使用ORM中的术语(“字段”、“关系”、“值”,而不是“命令”、“动词”、“值”)。也没有意识到您可以在parseAction中修改结果并添加其他内容-这里有很多好东西,再次感谢!
[['command', [Contains(value='thing'), NotContains(value='other_thing'), StartsWith(value='third_thing')]]]
[0]:
['command', [Contains(value='thing'), NotContains(value='other_thing'), StartsWith(value='third_thing')]]
- command: 'command'
- verbs: [Contains(value='thing'), NotContains(value='other_thing'), StartsWith(value='third_thing')]