python - Pyparsing parseaction 和列表类型错误
问题描述
对于一种小型语言,我想解析形式的表达式,"X [Y,Z,V]"
其中X
, Y
, Z
,V
是自然数。
下面是我的尝试。
from pyparsing import *
class Y():
def __init__(self, ls):
self.ls = ls
def MakeCombinedList(tokens):
print(len(tokens)) # prints 4
print(tokens) # [5, 1, 2, 3]
clist = tokens[1]
clist.append(tokens[0]) # 'int' attribute object has no attribute 'append'
return clist
def MakeIntList(tokens):
nlist = tokens[0].split(",")
ilist = []
for n in nlist:
ilist.append(int(n))
return ilist
def MakeY(tokens):
Yobj = Y(tokens[0])
return Yobj
LEFT_BRACK = Suppress(Literal("["))
RIGHT_BRACK = Suppress(Literal("]"))
NATURAL = Word(nums).addParseAction(lambda n: int(n[0]))
NATURAL_LIST = delimitedList(NATURAL, combine = True)
NATURAL_VEC = LEFT_BRACK + NATURAL_LIST + RIGHT_BRACK
NATURAL_VEC.addParseAction(MakeIntList)
X = NATURAL + NATURAL_VEC
X.addParseAction(MakeCombinedList)
Y = X
Y.addParseAction(MakeY)
print(Y.parseString("5 [1,2,3]").ls)
MakeIntList
应该将字符串"1,2,3"
转换为 list [1,2,3]
。
MakeCombinedList
然后应该将一个整数附加到此列表中,但tokens
接收到MakeCombinedList
的不是单个整数和从 创建的整数列表MakeIntList
,而是所有整数的列表,如我的评论所示。
我怎样才能让tokens[1]
insideMakeCombinedList
成为调用的结果MakeIntList
?
解决方案
这两行相互影响,因为您使用第一行将单独的数字字符串解析为整数,然后第二行将它们组合回逗号分隔的字符串。
NATURAL = Word(nums).addParseAction(lambda n: int(n[0]))
NATURAL_LIST = delimitedList(NATURAL, combine=True)
您正在寻找的功能是Group
:
NATURAL = Word(nums).addParseAction(lambda n: int(n[0]))
NATURAL_LIST = Group(delimitedList(NATURAL))
NATURAL_VEC = LEFT_BRACK + NATURAL_LIST + RIGHT_BRACK
# no MakeIntList parse action required
现在不是创建一个新字符串然后在解析操作中重新解析它,而是Group
告诉 pyparsing 生成结果标记的子结构。
这里也有一些混乱:
Y = X
Y.addParseAction(MakeY)
这将从Y
顶部定义的类重新定义为 pyparsing 表达式,并且在尝试访问其ls
属性时会得到一些奇怪的回溯。
Y_expr = X
Y_expr.addParseAction(MakeY)
我编写的runTests
方法是为了更轻松地进行简单的表达式测试和打印,而无需处理 Py2/Py3 打印差异:
Y_expr.runTests("""\
5 [1,2,3]
""")
显示:
5 [1,2,3]
[<__main__.Y object at 0x00000241C57B7630>]
由于您的 Y 类仅使用默认__repr__
行为,因此如果您定义自己的,则可以更好地查看内容:
class Y():
def __init__(self, ls):
self.ls = ls
def __repr__(self):
return "{}: {}".format(type(self).__name__, vars(self))
现在 runTests 显示:
5 [1,2,3]
[Y: {'ls': 5}]
如果 Y 类的目的只是为解析字段提供属性名称,请考虑使用结果名称:
X = NATURAL('ls') + NATURAL_VEC
Y_expr = X
#~ Y_expr.addParseAction(MakeY)
# what you had written originally
print(Y_expr.parseString("5 [1,2,3]").ls)
只会打印:
5
推荐阅读
- swift - iOS Danielgindi 图表中的 EXC_BAD_ACCESS (code=1, address=0x) ChartDataSet 条目
- c++ - 删除指针后的C++
- git - 推送到 DAGsHub 时出现 401
- elasticsearch - 如何使用 helm 将“冷数据节点”添加到 elasticsearch 集群?
- java - 是两个字谜吗?
- android - 如何在Android中分屏Camera 2
- html - 如何使这个嵌入式谷歌工作表代码响应?
- java - MethodHandle 强制转换返回类型
- python - Tkinter - 扫描并列出文件夹中的所有图像并加载它们
- c - 在子进程中将 dev/null 设置为标准输出有什么意义