Scala:以递归方式解析检查多个字符串的文件的最简洁方法

时间:2011-01-07 20:27:52

标签: string file scala

我想编写一个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))))

3 个答案:

答案 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行的滑动窗口来获取派生迭代器,您可以在其中查找i行和i+2上的字符串。

exists测试此滑动迭代器的元素是否满足谓词。为方便起见,case将模式匹配从滑动窗口元素的3行到3个val。 我必须使用REPL来找出滑动实际返回的类型

最后不要忘记关闭src。

如果您需要事件计数:

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

您可以过滤事件,然后获取尺寸......

编辑了短于3行的文件的匹配错误

答案 1 :(得分: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)

因为否则,Scala会对无效的UTF-8编码进行禁止。

答案 2 :(得分:1)

它需要精炼来处理短于3行的文件,但是在第一次尝试时我会尝试这样的事情:

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

然后

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

道歉如此简短,我正在接听我的手机......