Scalaのパーサコンビネータを使ってみました。いくつかパーサがありますから、対象データや実行したい処理に応じて、どれが適しているかを考えながら使う必要があります。
要点だけ。RegexParsersを使うと正規表現でいろいろと表現ができるので便利です。終端記号などを手っ取り早く表現するのに使えそうです。行末はcrlfで定義しています。各行は値vをカンマ「,」で区切っていると定義しています。値には英数字しか許していません。RegexParsersでは、skipWhitespaceをfalseにしないと空白(0x30,改行コード,タブコードなど)を読み飛ばしてしまいます。これにきづかずはまりました…
package org.sssg.soft.scala.sample.combinator.parsing.csv import scala.util.parsing.combinator.RegexParsers import java.io.FileReader // 単純な方法 class CsvParsers extends RegexParsers { def values : Parser[Any] = rep(line <~ crlf) def crlf : Parser[Any] = """(\r\n|\n|\r)""".r def line : Parser[Any] = v~rep(","~>v) def v : Parser[Any] = """[0-9a-zA-Z]*""".r override val skipWhitespace = false } object CsvParsersRunner { def main(args: Array[String]) { val parser = new CsvParsers(); val reader = new FileReader("sample.csv") println(parser.parseAll(parser.values, reader)) } }
このバージョンは簡易版なので、「,」でしか区切りを判断していないので、RFC4180で定義されているようなCSVデータを正しく区切ることはできません。これぐらいだと、JavaのStringTokenizerと同レベルなので、ありがたみはあまり感じないかもしれません。ただ、解析器のプログラムの見通しがすごく良いというのに注目すると、パーサコンビネータの強力さが何となくわかるはずです。