我正在用clojure编写一个小解析器以用于学习目的。
基本上是一个TSV文件解析器,需要放在数据库中,但是我增加了一个麻烦。
复杂的是,在同一文件中有更多的时间间隔。
该文件如下所示:
###andreadipersio 2010-03-19 16:10:00###
USER COMM PID PPID %CPU %MEM TIME
root launchd 1 0 0.0 0.0 2:46.97
root DirectoryService 11 1 0.0 0.2 0:34.59
root notifyd 12 1 0.0 0.0 0:20.83
root diskarbitrationd 13 1 0.0 0.0 0:02.84`
....
###andreadipersio 2010-03-19 16:20:00###
USER COMM PID PPID %CPU %MEM TIME
root launchd 1 0 0.0 0.0 2:46.97
root DirectoryService 11 1 0.0 0.2 0:34.59
root notifyd 12 1 0.0 0.0 0:20.83
root diskarbitrationd 13 1 0.0 0.0 0:02.84
我最终得到了这段代码:
(defn is-header?
"Return true if a line is header"
[line]
(> (count (re-find #"^\#{3}" line)) 0))
(defn extract-fields
"Return regex matches"
[line pattern]
(rest (re-find pattern line)))
(defn process-lines
[lines]
(map process-line lines))
(defn process-line
[line]
(if (is-header? line)
(extract-fields line header-pattern))
(extract-fields line data-pattern))
我的想法是在“生产线”间隔中需要与数据合并,所以我有这样的事情:
('andreadipersio', '2010-03-19', '16:10:00', 'root', 'launchd', 1, 0, 0.0, 0.0, '2:46.97')
对于每一行,直到下一个间隔,但我无法弄清楚如何做到这一点。
我尝试过这样的事情:
(def process-line
[line]
(if is-header? line)
(def header-data (extract-fields line header-pattern)))
(cons header-data (extract-fields line data-pattern)))
但是,这并不异常(exception)。
有什么提示吗?
谢谢!
最佳答案
您正在执行(> (count (re-find #"^\#{3}" line)) 0)
,但是您可以执行(re-find #"^\#{3}" line)
并将结果用作 bool 值。如果匹配失败,re-find
返回nil
。
如果要遍历集合中的项目,并且想跳过某些项目或将原始项目中的两个或多个项目合并为一个项目,那么有99%的时间需要reduce
。这通常最终非常简单。
;; These two libs are called "io" and "string" in bleeding-edge clojure-contrib
;; and some of the function names are different.
(require '(clojure.contrib [str-utils :as s]
[duck-streams :as io])) ; SO's syntax-highlighter still sucks
(defn clean [line]
(s/re-gsub #"^###|###\s*$" "" line))
(defn interval? [line]
(re-find #"^#{3}" line))
(defn skip? [line]
(or (empty? line)
(re-find #"^USER" line)))
(defn parse-line [line]
(s/re-split #"\s+" (clean line)))
(defn parse [file]
(first
(reduce
(fn [[data interval] line]
(cond
(interval? line) [data (parse-line line)]
(skip? line) [data interval]
:else [(conj data (concat interval (parse-line line))) interval]))
[[] nil]
(io/read-lines file))))
关于clojure - 使用Clojure解析数据,间隔问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2538326/