2011-01-07 24 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。