1

オブジェクトのテキスト表現を含むファイルがあります。テキストを解析してオブジェクトを返すコンビネーターパーサー文法を作成しました。本文中の「#」はコメント区切り文字です。その文字から行末まではすべて無視されます。空白行も無視されます。非常に大きなファイルを処理できるように、一度に1行ずつテキストを処理したいと思います。

パーサーの文法を一般的なコメントと空白行のロジックで乱雑にしたくありません。前処理ステップとしてこれらを削除したいと思います。ファイルを行上のイテレータに変換すると、次のようになります。

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

そのような式の出力をコンビネーターパーサーに渡すにはどうすればよいですか?Readerこのようなフィルタリングされた式からオブジェクトを作成する方法がわかりません。JavaFileReaderインターフェースはそのようには機能しません。

これを行う方法はありますか、それともパーサー文法にコメントと空白行のロジックを入れる必要がありますか?後者の場合、util.parsingすでにこれを行っているパッケージはありますか?

4

2 に答える 2

3

これを行う最も簡単な方法は、次のfromLinesメソッドを使用すること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あなたがあなたのパーサーに差し込むことができるものを持っています。とにかく、これは基本的に、を解析するときに起こることです。java.io.Readerすぐに。にラップされます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に対してイテレーターを生成します。これをに変換して、新しいを作成するために使用できます。デフォルトで削除されるため、追加が必要です(行が適切に分離されないため、使用が機能しない場合があります)。IterableSourceSEPgetLines\nSource

フィルタリングも適用する場合、つまり一部の行を削除する場合は、たとえば次のことを試してください。

// 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 に答える