[英]PyParsing a string representing a function
我有一个看起来像这样的数据:
data = 'person(firstame="bob", lastname="stewart", dob="2010-0206", hobbies=["reading, singing", "drawing"], is_minor=True)'
我编写了语法分析规则,如下所示:
quotedString.setParseAction(removeQuotes)
list_of_names = delimitedList(quotedString)
person_start = Literal("person(").suppress()
first = Literal("firstname") + Suppress("=") + quotedString
lastname = Literal("lastname") + Suppress("=") + quotedString
dob = Literal("dob") + Suppress("=") + quotedString
hobbies = Literal("hobbies") + Suppress("=[") + list_of_names + Suppress("]")
is_minor = Literal("is_minor") + Suppress("=") + oneOf("True False")
person_end = Suppress(")")
comma = Literal(",").suppress()
my_data = person_start + first + comma + last + comma + dob +comma + hobbies + comma + is_minor + person_end
result = my_data.parseString(data)
我的问题是3:
您应该真正将其分解,这样它就不会过多地依赖于文字了...因此,请寻找使“ X = Y”更通用的标记...
另外,另一种选择(因为您似乎正在尝试解析Python函数调用)是:
data = 'person(firstame="bob", lastname="stewart", dob="2010-0206", hobbies=["reading, singing", "drawing"], is_minor=True)'
import ast
d = {}
for kw in ast.parse(data).body[0].value.keywords:
if isinstance(kw.value, ast.List):
d[kw.arg] = [el.s for el in kw.value.elts]
else:
d[kw.arg] = getattr(kw.value, {ast.Name: 'id', ast.Str: 's'}[type(kw.value)])
# {'dob': '2010-0206', 'lastname': 'stewart', 'is_minor': 'True', 'firstame': 'bob', 'hobbies': ['reading, singing', 'drawing']}
您发布的代码中有一些次要的拼写错误(数据中的firstame="bob"
与firstname="bob"
, lastname
与last
),但是清理它们之后,看起来不错。 如果打印出结果,您将得到:
['firstname', 'bob', 'lastname', 'stewart', 'dob', '2010-0206',
'hobbies', 'reading, singing', 'drawing', 'is_minor', 'True']
首先,让我建议,就像您将list_of_names
定义为可能的值类型一样(从您之前的SO问题pyparsing带引号的字符串中 )定义为解析True / False值的布尔值。 使用oneOf
很好,让我们添加一个解析动作,将字符串“ True”和“ False”转换为实际的Python布尔值:
boolean_value = oneOf("True False").setParseAction(lambda t: t[0]=='True')
这类似于在quotedString上使用removeQuotes
。
现在,解析的结果现在看起来像:
['firstname', 'bob', 'lastname', 'stewart', 'dob', '2010-0206',
'hobbies', 'reading, singing', 'drawing', 'is_minor', True]
请注意,True现在不是字符串,而是Python值True
(该值周围没有引号)。
现在到您的问题的第一部分,如何使它成为命令。 Pyparsing允许您为语法的不同部分定义结果名称,以便在解析数据之后,您可以按名称访问这些值。 这样做的语法曾经是调用方法setResultsName
:
my_data = person_start + first.setResultsName("firstname") +
last.setResultsName("lastname") + ...
我发现这有点麻烦,并且使用所有“ .setResultsName”方法调用都很难读取该表达式。 所以不久前,我更改了API以接受以下语法:
my_data = person_start + first("firstname") + last("lastname") + ...
但是您定义为first
, last
等的内容不仅包含值,还包含标签。
简化语法的一种方法是制作自己的小助手方法,我们称其为named_parameter
:
def named_parameter(label, paramtype):
expr = Literal(label) + Suppress('=') + paramtype(label)
return expr
注意, label
用于指定文字字符串和值的结果名称。 现在,您可以将语法定义为:
first = named_parameter("firstname", quotedString)
last = named_parameter("lastname", quotedString)
dob = named_parameter("dob", quotedString)
hobbies = named_parameter("hobbies", Suppress("[") + list_of_names + Suppress("]"))
is_minor = named_parameter("is_minor", boolean_value)
使用命名的值,然后可以将解析的结果作为Python dict访问:
print result["firstname"]
print result["hobbies"]
打印:
bob
['reading, singing', 'drawing']
或者,如果您愿意,也可以使用对象属性表示法:
print result.firstname
print result.hobbies
为了回答问题的第二部分,您询问了如何处理参数可能混乱的情况。 最简单的方法是再次使用delimitedList
:
parameter = first | last | dob | hobbies | is_minor
my_data = person_start + delimitedList(parameter) + person_end
这不是严格的解析器,它将接受不具有所有参数的参数列表,或具有重复参数的列表。 但是对于现有的有效代码,它将以任何顺序解析带有参数的列表。
这是最终的解析器:
quotedString.setParseAction(removeQuotes)
list_of_names = delimitedList(quotedString)
boolean_value = oneOf("True False").setParseAction(lambda t: t[0]=='True')
def named_parameter(label, paramtype):
expr = Literal(label) + Suppress('=') + paramtype(label)
return expr
person_start = Literal("person(").suppress()
first = named_parameter("firstname", quotedString)
last = named_parameter("lastname", quotedString)
dob = named_parameter("dob", quotedString)
hobbies = named_parameter("hobbies", Suppress("[") + list_of_names + Suppress("]"))
is_minor = named_parameter("is_minor", boolean_value)
person_end = Suppress(")")
comma = Literal(",").suppress()
parameter = first | last | dob | hobbies | is_minor
my_data = person_start + delimitedList(parameter) + person_end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.