instaparse如何遍历解析树
How to traverse parse tree from instaparse
我正在试验 Clojure 和 Instaparse。我创建了一种小型玩具语言,但我对如何正确处理生成的树感到困惑。这就是我得到的:
[:ClassDescription
[:ClassName "Test"]
[:Properties
[:Property
[:PropertyName "ID"]
[:PropertyType "Int"]]
[:Property
[:PropertyName "Name"]
[:PropertyType "string"]]]]
现在,作为示例,我想提取所有 PropertyType。我有两个主要方法,我想要一个解决方案。
- 通过指定路径;像
[:ClassDescription
:Properties :Property :PropertyType]
- 通过提取所有
:PropertyType
个元素,不考虑深度。
对于 A.,我的第一个想法是通过 insta/transform
将它的某些部分转换为地图,然后使用 get-in
,但后来我得到了一个非常笨拙的解决方案,涉及嵌套循环和 get-in
.
我也可以用nth
,把自己钻进结构里,不过好像很麻烦,再加一层就容易坏
我的另一个想法是递归解决方案,我以相同的方式处理每个元素并遍历它并检查所有匹配项。
对于 B,到目前为止,我唯一的解决方案是一个递归函数,它只钻取所有内容并尝试匹配第一个元素。
我相信这些 "handwritten" 函数可以通过 insta/transform
、map
、filter
、reduce
等的巧妙组合来避免。可以是吗?
要从解析的数据中获取元素,您可以使用 tree-seq
遍历所有元素并选择您需要的元素。例如:
(defn parsed-tree-seq [parsed]
(tree-seq #(vector? (second %)) rest parsed))
(map second
(filter
#(= (first %) :PropertyType)
(parsed-tree-seq parsed)))
; => ("Int" "string")
然而,您最好首先在解析器中使用 <...>
来塑造您的数据 and/or 通过将它们变成更具地图感的东西,这样更容易访问转型。例如。将 :Properties
变成地图列表并将整个事物变成地图:
(defn transform [parsed]
(insta/transform
{:Property #(into {} %&)
:Properties #(vec (concat [:Properties] [%&]))
:ClassDescription #(into {} %&)
} parsed))
(map :PropertyType (:Properties (transform parsed)))
; => ("Int" "string")
我正在试验 Clojure 和 Instaparse。我创建了一种小型玩具语言,但我对如何正确处理生成的树感到困惑。这就是我得到的:
[:ClassDescription
[:ClassName "Test"]
[:Properties
[:Property
[:PropertyName "ID"]
[:PropertyType "Int"]]
[:Property
[:PropertyName "Name"]
[:PropertyType "string"]]]]
现在,作为示例,我想提取所有 PropertyType。我有两个主要方法,我想要一个解决方案。
- 通过指定路径;像
[:ClassDescription :Properties :Property :PropertyType]
- 通过提取所有
:PropertyType
个元素,不考虑深度。
对于 A.,我的第一个想法是通过 insta/transform
将它的某些部分转换为地图,然后使用 get-in
,但后来我得到了一个非常笨拙的解决方案,涉及嵌套循环和 get-in
.
我也可以用nth
,把自己钻进结构里,不过好像很麻烦,再加一层就容易坏
我的另一个想法是递归解决方案,我以相同的方式处理每个元素并遍历它并检查所有匹配项。
对于 B,到目前为止,我唯一的解决方案是一个递归函数,它只钻取所有内容并尝试匹配第一个元素。
我相信这些 "handwritten" 函数可以通过 insta/transform
、map
、filter
、reduce
等的巧妙组合来避免。可以是吗?
要从解析的数据中获取元素,您可以使用 tree-seq
遍历所有元素并选择您需要的元素。例如:
(defn parsed-tree-seq [parsed]
(tree-seq #(vector? (second %)) rest parsed))
(map second
(filter
#(= (first %) :PropertyType)
(parsed-tree-seq parsed)))
; => ("Int" "string")
然而,您最好首先在解析器中使用 <...>
来塑造您的数据 and/or 通过将它们变成更具地图感的东西,这样更容易访问转型。例如。将 :Properties
变成地图列表并将整个事物变成地图:
(defn transform [parsed]
(insta/transform
{:Property #(into {} %&)
:Properties #(vec (concat [:Properties] [%&]))
:ClassDescription #(into {} %&)
} parsed))
(map :PropertyType (:Properties (transform parsed)))
; => ("Int" "string")