Scala: самый простой способ рекурсивного анализа файлов, проверяющих наличие нескольких строк - PullRequest
2 голосов
/ 07 января 2011

Я хочу написать скрипт 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 ]

7 голосов
/ 08 января 2011

Вы можете сделать что-то вроде этого:

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 значений. Мне пришлось использовать REPL, чтобы выяснить, какой тип действительно возвращает скольжение .

Наконец, не забудьте закрыть src.

Если вам нужен счетчик вхождений:

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

Вы фильтруете вхождения и затем получаете размер ...

, отредактированный для ошибки совпадения для файлов короче 3 строк

2 голосов
/ 08 января 2011

Вот альтернативный способ сделать это:

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.

1 голос
/ 08 января 2011

Требуется доработка, чтобы иметь дело с файлами короче 3 строк, но при первом ударе я бы попробовал что-то вроде этого:

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

Тогда

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

Извиняюсь за то, что был настолько кратким, я отвечаю на свой мобильный ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...