2

parboiled2を使用して、単一の CSV 文字列ではなく複数の CSV 行を解析したいと考えています。結果は次のようになります。

val parser = new CSVRecordParser(fieldSeparator)
io.Source.fromFile("my-file").getLines().map(line => parser.record.run(line))

ここで、CSVRecordParser は CSV レコードのパーボイルド パーサーです。私が抱えている問題は、パーボイルドパーサーは実行メソッドではなくコンストラクターでの入力を必要とするため、私が試したことではこれを行うことができないということです。したがって、行ごとに新しいパーサーを作成することもできますが、これは良くありません。または、すべての入力に対して入力をパーサーに渡す方法を見つけることもできます。入力を変数として設定し、パーサーを別のオブジェクトにラップすることで、パーサーを少しハックしようとしました

object CSVRecordParser {

  private object CSVRecordParserWrapper extends Parser with StringBuilding {

    val textBase = CharPredicate.Printable -- '"'
    val qTextData = textBase ++ "\r\n"

    var input: ParserInput = _
    var fieldDelimiter: Char = _

    def record = rule { zeroOrMore(field).separatedBy(fieldDelimiter) ~> (Seq[String] _) }
    def field = rule { quotedField | unquotedField }
    def quotedField = rule {
      '"' ~ clearSB() ~ zeroOrMore((qTextData | '"' ~ '"') ~ appendSB()) ~ '"' ~ ows ~ push(sb.toString)
    }
    def unquotedField = rule { capture(zeroOrMore(textData)) }
    def textData = textBase -- fieldDelimiter

    def ows = rule { zeroOrMore(' ') }
  }

  def parse(input: ParserInput, fieldDelimiter: Char): Result[Seq[String]] = {
    CSVRecordParserWrapper.input = input
    CSVRecordParserWrapper.fieldDelimiter = fieldDelimiter
    wrapTry(CSVRecordParserWrapper.record.run())
  }
}

そしてCSVRecordParser.parse(input, separator)、行を解析したいときに呼び出すだけです。これは恐ろしいことに加えて、機能せず、パーサーの以前の使用法に関連する奇妙なエラーがよく発生します。これは、parboiled2 を使用してパーサーを作成する方法ではないことを知っており、このライブラリでやりたいことを達成するための最良の方法は何かと考えていました。

4

2 に答える 2

2

レコードの終わりルールをパーサーに追加してみませんか。

def EOR = rule { "\r\n" | "\n" }

def record = rule { zeroOrMore(field).separatedBy(fieldDelimiter) ~ EOR ~> (Seq[String] _) }

次に、必要な数の行を渡すことができます。

于 2016-10-20T19:59:26.600 に答える