我在用Clojure和Instaparse做实验。我创造了一个小玩具语言,我被困在如何正确对待产生的树。我得到的是:
[:ClassDescription
[:ClassName "Test"]
[:Properties
[:Property
[:PropertyName "ID"]
[:PropertyType "Int"]]
[:Property
[:PropertyName "Name"]
[:PropertyType "string"]]]]现在,作为一个例子,我想提取所有的PropertyTypes。我有两种主要的方法,我想要解决这两种方法。
[:ClassDescription :Properties :Property :PropertyType]:PropertyType元素,而不考虑深度。对于A.,我的第一个想法是通过insta/transform将它的某些部分转换成映射,然后使用get-in,但之后我得到了一个非常笨拙的解决方案,涉及嵌套循环和get-in。
我也可以使用nth,并在结构中钻研我自己,但这似乎很麻烦,如果我添加另一个层,就会很容易崩溃。
我的另一个想法是一种递归解决方案,我以相同的方式对待每个元素,并循环遍历它并检查所有匹配项。
对于B,到目前为止,我唯一的解决方案是一个递归函数,它只需要遍历所有内容并尝试匹配第一个元素。
我相信这些“手写”函数可以通过insta/transform、map、filter、reduce等巧妙的组合来避免,可以吗?
发布于 2015-04-10 10:31:47
为了从解析的数据中获取元素,可以使用tree-seq迭代所有元素并选择所需的内容。例如:
(defn parsed-tree-seq [parsed]
(tree-seq #(vector? (second %)) rest parsed))
(map second
(filter
#(= (first %) :PropertyType)
(parsed-tree-seq parsed)))
; => ("Int" "string")然而,您最好首先通过在解析器中使用<...>和/或将数据转换成更易于访问的地图来格式化您的数据。例如,将:Properties转换成一个地图列表,并将整个事物转化为一张地图:
(defn transform [parsed]
(insta/transform
{:Property #(into {} %&)
:Properties #(vec (concat [:Properties] [%&]))
:ClassDescription #(into {} %&)
} parsed))
(map :PropertyType (:Properties (transform parsed)))
; => ("Int" "string")https://stackoverflow.com/questions/29556277
复制相似问题