2011-01-07 44 views
2

我想編寫一個Scala腳本遞歸處理目錄中的所有文件。對於每個文件,我想看看是否有任何情況下,在X行和X - 2行出現字符串。如果出現類似情況,我想停止處理該文件,並將該文件名添加到地圖的文件名到發生次數。我剛開始學習今天斯卡拉,我已經拿到了文件遞歸碼的工作,並且需要一些幫助,搜索字符串,這是我到目前爲止有:Scala:最簡潔的方式遞歸解析文件檢查多個字符串


import java.io.File 
import scala.io.Source 

val s1= "CmdNum = 506" 
val s2 = "Data = [0000,]" 

def processFile(f: File) { 
    val lines = scala.io.Source.fromFile(f).getLines.toArray 
    for (i = 0 to lines.length - 1) { 
    // want to do string searches here, see if line contains s1 and line two lines above also contains s1 
    //println(lines(i)) 
    } 
} 

def recursiveListFiles(f: File): Array[File] = { 
    val these = f.listFiles 
    if (these != null) { 
    for (i = 0 to these.length - 1) { 
     if (these(i).isFile) { 
     processFile(these(i)) 
     } 
    } 
    these ++ these.filter(_.isDirectory).flatMap(recursiveListFiles) 
    } 
    else { 
    Array[File]() 
    } 
} 

println(recursiveListFiles(new File(args(0)))) 

回答

7

你可以做這樣的事情:

def processFile(f: File) { 
    val src = Source.fromFile(f) 
    val hit = src.getLines().sliding(3).exists{ 
    case List(l0, l1, l2) => l0.contains(s1) && l2.contains(s1) 
    case _ => false 
    } 
    src.close 
    // do something depending on hit like adding to a Map 
} 

首先,您不需要轉換爲數組,您可以保留迭代器只讀取找到匹配所需的行。

您可以使用sliding使用3行滑動窗口來獲取派生迭代器,您可以在其中查找行ii+2上的字符串。

exists測試此滑動迭代器的元素是否滿足謂詞。爲了方便起見,case將模式匹配從滑動窗口元素到3個val的3條線。 我不得不使用REPL來找出什麼類型的滑動真的返回

最後別忘了關閉src。

如果需要出現計數:

val count = src.getLines().sliding(3).filter{ 
    case List(l0, l1, l2) => l0.contains(s1) && l2.contains(s1) 
    case _ => false 
    }.size 

您篩選中,然後再拿到大小...

編輯的匹配錯誤的文件短於3線

+0

感謝您的迴應,我試了一下,但得到一個異常時,它正在處理文件: –

+0

scala.MatchError:List(2010-05-31 17:31:06.015 UTC + 0000 INFO [xxx-HostSy ncThread -Runnable-> HostSync-176666318810351] estation.services.timesync.TimeSync - 與主機'http://www04.xxx.com:80'成功的時間同步:解析後的1275327066705分解到5月31日星期一的系統時間17 :31:06 UTC 2010) at Main $$ anon $ 1 $$ anonfun $ 1.apply(506。Scala:13) at Main $$ anon $ 1 $$ anonfun $ 1.apply(506.scala:13) at scala.collection.Iterator $ class.exists(Iterator.scala:655) at scala.collection.Iterator $ GroupedIterator.exists(Iterator.scala:772) –

+0

@fred,我添加了'case _ => false'來處理短文件。 – huynhjl

1

它需要細化處理短於3行的文件,但在第一次刺激時,我會嘗試這樣的事情:

def checkFile(file: File) = { 
    val lines = ... 
    (lines zip lines.tail.tail) exists { _1 = _2 } 
} 

然後

val files = ... 
val validFiles = files filter { checkFile } 

道歉這麼簡單,我回答我的手機......

+0

啊文件少於3行,這解釋了我的答案中的匹配錯誤:) – huynhjl

2

這裏是這樣做的另一種方式:

import java.io.File 
import scala.io.Source 

val s1= "CmdNum = 506" 

def filesAt(f: File): Array[File] = if (f.isDirectory) f.listFiles flatMap filesAt else Array(f) 

def filterFiles(arr: Array[File]) = arr filter (
    Source 
    fromFile _ 
    getLines() 
    sliding 3 
    exists { 
     case List(l1, l2, l3) => List(l1, l3) forall (_ contains s1) 
     case _ => false 
    } 
) 

println(filterFiles(filesAt(new File(args(0))))) 

雖然我」我會承認我有點欺騙。事實上,我不得不代替寫Source fromFile _此:

Source.fromFile(_)(scala.io.Codec.ISO8859) 

因爲,否則,斯卡拉將無效UTF-8編碼的BARF。