1

我有一个包含对象的文本表示的文件。我编写了一个组合器解析器语法来解析文本并返回对象。在文本中,“#”是注释分隔符:从该字符到行尾的所有内容都将被忽略。空行也被忽略。我想一次处理一行文本,这样我就可以处理非常大的文件。

我不想用通用注释和空行逻辑弄乱我的解析器语法。我想删除这些作为预处理步骤。通过行将文件转换为迭代器,我可以执行以下操作:

Source.fromFile("file.txt").getLines.map(_.replaceAll("#.*", "").trim).filter(!_.isEmpty)

如何将这样的表达式的输出传递给组合器解析器?我不知道如何Reader从这样的过滤表达式中创建一个对象。JavaFileReader接口不是这样工作的。

有没有办法做到这一点,或者我应该把我的评论和空行逻辑放在解析器语法中?如果是后者,是否有一些util.parsing包已经为我做了这个?

4

2 回答 2

3

最简单的方法是使用fromLineson 方法PagedSeq

import scala.collection.immutable.PagedSeq
import scala.io.Source
import scala.util.parsing.input.PagedSeqReader

val lines = Source.fromFile("file.txt").getLines.map(
  _.replaceAll("#.*", "").trim
).filterNot(_.isEmpty)

val reader = new PagedSeqReader(PagedSeq.fromLines(lines))

现在你有了一个scala.util.parsing.input.Reader可以插入解析器的东西。无论如何,这本质上就是解析 a 时发生的事情java.io.Reader——它立即被包裹在 a 中PagedSeqReader

于 2012-11-12T21:33:12.383 回答
0

这不是你写过的最漂亮的代码,但你可以通过Source如下新代码:

val SEP = System.getProperty("line.separator")
def lineMap(fileName : String, trans : String=>String) : Source = {
  Source.fromIterable(
    Source.fromFile(fileName).getLines.flatMap(
      line => trans(line) + SEP
    ).toIterable
  )
}

解释:flatMap将产生一个关于characters的迭代器,你可以把它变成一个Iterable,你可以用它来构建一个新的Source. 您需要额外的SEP,因为getLines默认情况下会删除它(使用\n可能无法正常工作,因为Source无法正确分隔行)。

如果您也想应用过滤,即删除一些行,您可以尝试:

// whenever `trans` returns `None`, the line is dropped.
def lineMapFilter(fileName : String, trans : String=>Option[String]) : Source = {
  Source.fromIterable(
    Source.fromFile(fileName).getLines.flatMap(
      line => trans(line).map(_ + SEP).getOrElse("")
    ).toIterable
  )
}

举个例子:

lineMapFilter("in.txt", line => if(line.isEmpty) None else Some(line.reverse))

...将删除空行并反转非空行。

于 2012-11-12T21:01:22.497 回答