使用Scala Parser解析JSON

本文来自: http://fair-jm.iteye.com 转截请注明出处

 

最近几天看了些文章(Learn by Example: Scala Parser Combinators,An Introduction To Scala Parser Combinators )学习了scala中的Parser的一些使用 这边以一个解析JSON的例子来记录一些笔记

 

首先是一些连接符(翻译自第一篇文章):

  • | 选择连接符,当左边或右边的Parser成功时成功。
  • ~ 序列连接符,当左右的Parser都成功时成功
  • ~> 和~类似 不同的是左边的结果不会包含在最后的结果中
  • <~ 和~类似 右边的结果不会包含在最后的结果中
  • ^^ 转换连接符,当左边的操作成功时可以通过这个连接符操作结果
  • rep repeat的意思 重复

 

如果说看起来比较难懂的话 在使用之后就会觉得容易理解得多

我没有学过编译原理(选修课没选惭愧...听到别人说一星期两节课要上两章就退缩了...) 对一些专用术语不是很理解 这边的Parser使用更加像是使用正则表达式(这主要也有继承了RegexParser的因素在)

 

首先看JSON的组成 从ECMA-404的文档中可以看到:


使用Scala Parser解析JSON_第1张图片
 主要有 object array number string bool(true|false) null 这几个元素构成

 

为了编码方便 我让类继承自JavaTokenParsers:

class JsonParser extends JavaTokenParsers

 对以上一些元素进行了定义(和ECMA-404的规范有些许差别 其实很多地方需要重写正则表达式的...)

//来自JavaTokenParser的floatingPointNumber parser
  def jNum: Parser[Double] = floatingPointNumber ^^ (_.toDouble) 

//stringLiteral 也来自JavaTokenParser 这边解析出来的结果会是例如"string"的形式 我们需要把双引号给去掉
  def jStr: Parser[String] = stringLiteral ^^ (s => s.substring(1, s.length() - 1)) 

//正则表达式会被隐式转换为Parser 
  def jBool: Parser[Boolean] = "(true|false)".r ^^ (_.toBoolean)

  def jNull: Parser[Null] = "null".r ^^ (t => null)

 

接下去还差对object和array的定义

在ECMA-404中他们的定义如下:


使用Scala Parser解析JSON_第2张图片
 
使用Scala Parser解析JSON_第3张图片
 其中他们内的value是可以包括所有类型的(包括object和array)

可能有多个 这样需要用到rep连接符

 

具体的编码不是很困难 scala的模式匹配用起来比较舒服:

这边将JsonArray转化为List的形式 将JsonObject转换为Map的形式:

  def term = jsonArray | jsonObject | jNum | jBool | jNull | jStr
  def jsonArray: Parser[List[Any]] = "[" ~> rep(term <~ ",?".r) <~ "]" ^^ (l => l)

//String也会被隐式转化为Parser的形式
  def jsonObject: Parser[Map[String, Any]] = "{" ~> rep((ident ~ ":" ~ jNum |
    ident ~ ":" ~ jBool | ident ~ ":" ~ jNull | ident ~ ":" ~ jsonObject | ident ~ ":" ~ jsonArray | ident ~ ":" ~ jStr) <~ ",?".r) <~ "}" ^^ {
    os =>
      var map = Map[String, Any]()
      os.foreach(o =>
        o match {
          case k ~ ":" ~ v => map = map ++ Map(k -> v)
        })
      map

  }

 

 

最后来实验一下:


使用Scala Parser解析JSON_第4张图片
 虽然number的形式有点问题(我用了JavaTokenParser中的一个Parser) 但总体结果还是正确的 使用起来也是相当简单

 

对于解析JSON来说 用scala提供的Parser并不困难 本文并未对其中的原理有任何描述 可以看上面参考的第二篇文章 里面有比较详尽的分析 

 

希望对初学scala的Parser的人有所帮助^_^

 

你可能感兴趣的:(scala学习笔记)