2011-12-06 19 views
2

我想分析和過濾,看起來像這樣的文件:的Clojure:斬第一空間分隔的字符

@@1 Row one. 
@@2 Row two. 

我已經能夠做到用下面的代碼行的過濾:

(defn parse-text-cms [sel-row] 
    (let [f_data (st/split #"@@" (slurp "cms/tb_cms.txt"))] 
    ;(prn (map #(take 1 %) f_data)))) 
    (filter #(= (first (take 1 %)) sel-row) f_data))) 

然而,這個代碼給我(如果SEL-ROW = 1):

1 Row one. 

我想砍掉的是1和SPAC e後,所以有:

Row one. 

我認爲有一些序列魔術來做到這一點。我無法想出一個優雅的解決方案。

回答

2

我會定義函數的方式如下:

(defn parse-text-cms [sel-row] 
    (with-open [input (clojure.java.io/reader "cms/tb_cms.txt")] 
    (first 
    (for [[_ number line] (map (partial re-find #"@@(\d)+\s+(.*)") 
           (line-seq input)) 
      :when (= number (str sel-row))] 
     line)))) 

line-seqreader的結合使我從輸入文件行的序列。 with-open確保當我做了正確的關閉文件。我申請一個正則表達式每個查找@@後跟一個數字和一些空格線。

re-find返回一個向量,其具有三個項目:

  • 整個匹配線
  • 的數目(在正則表達式的第一組)
  • 的行的其餘部分(第二組中的正則表達式)

我結合這些以numberlinefor語句中使用解構(我沒有興趣在日整個匹配線,所以我忽略了)。我使用:when過濾所選sel-row和屈服僅line(的其餘部分)。

由於我只希望在文件中找到一個匹配項,我只返回for構建的序列中的第一項。由於formapline-seq懶惰的,該項目被發現後,它也停止文件的閱覽。

如果您對行進行了很多查找,我會建議將整個文件加載到內存中,而不是每次都讀取它。

+1

'reader'應該在周圍的'with-open'形式中創建。 –

+0

當然。壞我!編輯。 –

+0

謝謝。我是clojure的新手,你能否提供有關內存加載的更多信息?也許有些文檔? – kfk

0

以前給出的答案使用line-seq和正則表達式組的解構適用於給定的用例。

在一般情況下,所有你想要的是字符串操作clojure.core包括subs函數。 http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/subs

subs是使用java interop和java String類的substring方法實現的。


user=> (subs "abcdef" 1) 
"bcdef" 
user=> (subs "abcdef" 2 4) 
"cd" 
1

另一種解決方案是使用函數解析器庫,如dj-peg(我寫的)。

https://github.com/bmillare/dj-peg

然後,你可以這樣寫:

(require '[dj-peg :as p]) 
(let [line "@@1 the remaining line\n" 
     initial (p/token #"@@\d+\s+)] 
     (second (p/parse initial line))) 

功能解析使用由P /標記分析的行中的文本返回解析器。它將返回一個具有第一個值作爲解析結果的矢量,第二個是剩餘的輸入。因此,如果我們稱第二,我們會得到其餘的線。運行此返回

"the remaining line\n" 

我建議檢出圖書館。它是用僞文字編程風格編寫的,所以源代碼閱讀非常流暢。通過源代碼後,您應該能夠理解解析模型。

相關問題