在Clojure中解析具有混合类型的文件的行

时间:2014-05-26 20:47:41

标签: parsing clojure

假设我的文件行显示为apple,pie,100,1000。从每一行我想有一个像["apple" "pie" 100 1000]这样的向量,其中前两个是字符串,第二个是整数或长整数或其他。

解决方案可能是

(defn foo [line]
  (let [[a b c d] (split line #",")]
    [a b (Integer/parseInt c) (Integer/parseInt d)]))

做了我想做的事,但我不确定是否有更好(或更惯用)的方式来做这件事。

从这个问题What's the easiest way to parse numbers in clojure?,我发现了clojure.edn,所以我可以像这样使用read-line

(map read-string (clojure.string/split "apple,pie,12,134" #","))
;=> (:apple :pie 12 134)

但是这给了我符号而不是字符串。

此问题Convert a sequence of strings to integers (Clojure)也类似,只是这些行只包含数字而不包含数字和字符串。

注意:clojure-csv(https://github.com/davidsantiago/clojure-csv)和clojure.data.csv(https://github.com/clojure/data.csv)似乎没有自动执行此操作的功能。

3 个答案:

答案 0 :(得分:3)

您可以使用data.csv来解析数据,使用Prismatic的schema将字段值强制转换为所需的类型:

;; [org.clojure/data.csv "0.1.2"]
;; [prismatic/schema "0.2.2"]

(require '[schema.core :as s]
         '[schema.coerce :as coerce]
         '[clojure.data.csv :as csv])

(def field-schemas [s/Str s/Str s/Int s/Int])
(def field-coercers
  (mapv coerce/coercer
    field-schemas
    (repeat coerce/string-coercion-matcher)))

(defn coerce-fields [fields]
  (mapv #(%1 %2) field-coercers fields))

最后:

(map coerce-fields (csv/read-csv "apple,pie,12,134"))
;= (["apple" "pie" 12 134])

答案 1 :(得分:0)

我认为那里有一个图书馆让这很容易。不记得它的名字,但它的工作原理如此

(let [structure [str str int int]]
 (map #(% %2) 
      structure
      (map read-string (clojure.string/split "apple,pie,12,134" #",")))
;=> ("apple" "pie" 12 134)

答案 2 :(得分:0)

不是很优雅,但是

(map numberise (clojure.string/split "apple,pie,12,134" #","))
; ("apple" "pie" 12 134)

,其中

(defn numberise [s]
  (try (Integer/parseInt s)
       (catch NumberFormatException nfe s)))