Scala 2.6.0-RC1 でscala.util.parsing.combinatorが標準パッケージになりました。というわけでリファレンスとちょっとしたサンプルくらしかなかったのだけど、とりあえず書いてみた。
どう書く?orgに投稿した、ExcelライクCSVのパーサ。
scala code
import scala.util.parsing.combinator.{Parsers, ImplicitConversions, ~, mkTilde}import scala.util.parsing.input.CharArrayReaderimport Character.isISOControlobject CSVParser {trait Basecase class Field(s:String) extends Base {override def toString = s}case class Record(fields: List[Field]) extends Basecase class File(records :List[Record]) extends Basedef mkString(cs :List[Any]) = cs.mkString("")class CSVParser extends Parsers {type Elem = Chardef notMeta(c:Elem) = c!=',' && c!='\n' && c!='"' && !isISOControl(c)lazy val file = record.*('\n') ^^ Filelazy val record = (field|quotedField|nullableField).*(',') ^^ Recordlazy val field = chars.+ ^^ {cs => Field(mkString(cs))}lazy val nullableField = chars.* ^^ {cs => Field("")}lazy val quotedField = '"' ~ (charsInQuote|quoteInQuote).* ~ '"' ^^ {cs => Field(mkString(cs))}lazy val charsInQuote = elem("chars in field", _!='"')lazy val quoteInQuote = repN(2, quote) ^^ {cs => '"'}lazy val quote = '"' ^^ successlazy val chars = elem("chars", notMeta)}}val data = """"aaa","bbb","ccc",zzz,"y""Y""y",xxx""".trim(new CSVParser.CSVParser).file(newCharArrayReader(data.toCharArray)).map(file => {file.records.map({record =>val fields = record.fields(1 to fields.length).foreach(i => println(i +" => " + fields(i-1)))})})
とりあえずこんな感じ。これはダイレクトにParsersクラスを直接継承してるけど、StdTokenParsersってかんじのParserもあるし、StdLexicalってかんじなLexerもあってこれはなかなか。
時間が出来たらもうちょっといじってみよう。よさげな解説してるサイトがあったら是非教えてください。
No comments yet
trackback uriLeave a Comment