在Clojure中,如何从文本文件读取分层数据结构?

时间:2018-07-29 02:51:03

标签: json data-structures clojure

我有一个文本文件,其内容如下:

section1
    name=test
    value
        attr1=v1
        attr2=v2

section2
    age=20
    prop
        attr3=v3

我想读取它,并将其呈现为树数据结构(或JSON),例如:

{:section1
    {:name "test"
     :value {:attr1 "v1"
             :attr2 "v2" }}
 :section2
    {:age 20
     :prop {:attr3 "v3" }}
}

我如何在没有额外lib的情况下使用核心clojure进行操作?我发现很难对付 处理分层数据结构中处于中间状态。

1 个答案:

答案 0 :(得分:1)

首先,您需要一个用于解析行的函数:

(defn parse-lines [s]
  (->> (clojure.string/split-lines s)
       (remove empty?)
       (map #(re-matches #"( *)([^ =]+)(?:=(.+))?" %))
       (map (fn [[_ level key value]]
              [(-> (or level "")
                   (count)
                   (quot 4))
               (keyword key)
               value]))))



(parse-lines content)
;; =>
([0 :section1 nil]
 [1 :name "test"]
 [1 :value nil]
 [2 :attr1 "v1"]
 [2 :attr2 "v2"]
 [0 :section2 nil]
 [1 :age "20"]
 [1 :prop nil]
 [2 :attr3 "v3"])

然后,您需要一个在行上递归迭代并创建嵌套地图的函数:

(defn reduce-lines [lines]
  (loop [[x & xs] lines
         path []
         prev-key nil
         result {}]
    (if-let [[l k v] x]
      (let [indent (- (count path) l)
            path (case indent
                   0 path
                   -1 (conj path prev-key)
                   (->> path (drop indent) vec))]
        (recur xs path k (assoc-in result (conj path k) v)))
      result)))



(reduce-lines (parse-lines content))
;; => 
{:section1 {:name "test", :value {:attr1 "v1", :attr2 "v2"}}, 
 :section2 {:age "20", :prop {:attr3 "v3"}}}

请注意,没有缩进和内容格式错误的声明。