Haskell Json数据处理
json的基本类型为——string, numbers, Booleans以及null,定义json类型如下
-- file: Json.hs
module Json where
data JValue = JString String
| JNumber Double
| JBool Bool
| JNull
| JObject [(String, JValue)]
| JArray [JValue]
deriving(Eq, Ord, Show)
打印Json类型数据
-- file: PutJson.hs
module PutJson where
import Data.List (intercalate)
import Json
renderJValue :: JValue –> String
renderJValue (JString s) = show s
renderJValue (JNumber n) = show n
renderJValue (JBool True) = “true”
renderJValue (JBool False) = “false”
renderJValue JNull = “null”
renderJValue (JObject o) = "{" ++ pairs o ++ "}"
where pairs [] = ""
pairs ps = intercalate "," (map renderPair ps)
renderPair (k, v) = show k ++ ":" ++ renderJValue v
renderJValue (JArray a) = "[" ++ values a ++ "]"
where values [] = ""
values vs = intercalate "," (map renderJValue vs)
putJValue :: JValue –> IO()
putJValue v = putStrLn (renderJValue v)
最后编写调用文件
-- file: Main.hs
module Main where
main = putJValue (JObject [("foo", JNumber 1), ("bar", JBool False)])
在命令行中输入如下指令
ghc –o demo Json.hs PutJson.hs Main.hs
生成demo.exe,然后在命令行中输入demo,即可得到JValue的打印字符串。如果JValue的值结构非常复杂,则通过这种方法打印出来显得对人类不够友好。那么,如何友好的打印出来呢?
假设我们有一个模块Prettify,这个模块的API将JValue转换为Doc而不是上面的String,我们重写render函数如下,
-- file: PrettyJson.hs
renderJValue :: JValue –> Doc
renderJValue (JBool True) = text “true”
renderJValue (JBool False) = text “false”
renderJValue JNull = text “null”
renderJValue (JNumber num) = double num
renderJValue (JString str) = string str
其中,Doc类型,text,double和string函数由我们的Prettify模块实现。
先给出string函数的定义
-- file: PrettyJson.hs
string :: String –> Doc
string = enclose '"' '"' . hcat . map oneChar
这个定义中使用了自由点风格(自由点风格),本来函数是从左向右运算的,使用自由点风格后,等价于
-- file: PrettyJson.hs
string :: String –> Doc
string s = enclose '"' '"' (hcat (map oneChar s)) (1)
可以看出,使用这种风格,省去参数s,并将小括号替换为点号。这个定义中,出现了各种函数,现在来依次分解。enclose函数是在一个Doc对象的前面和后面分别附加字符,其定义如下
-- file: PrettyJson.hs
enclose :: Char –> Char –> Doc –> Doc
enclose left right x = char left <> x <> char right
char是一个函数,用于将一个Char字符类型转换为Doc类型,目前我们还不知道其方法体,先用undefined表示其方法体,这样, 签名如下,
-- file: PrettyJson.hs
char :: Char –> Doc
char c = undefined
<>是一个中缀函数,写在两个运算分量中间时,看作一个运算符,其运算优先级比作为函数的char底,故enclose函数方法体可以这么看,char函数将Char字符类型参数left和right转换为两个Doc类型参数,然后与另一个Doc类型参数 x 用两个 <> 运算符连接,容易知道,<>连接两个Doc类型参数,得到另一个Doc类型结果,签名如下,其实,这个<>运算符类似于String类型的(++)运算符,即连接两个Doc参数,生成一个新的Doc类型结果。
-- file: PrettyJson.hs
(<>) :: Doc –> Doc –> Doc
a <> b = undefined
我们再看(1),现在可以知道string函数的作用就是对(hcat (map oneChar s)) 这个Doc类型值两边添加双引号 ("),于是我们接着看hcat函数,这个函数类似于list的连接函数concat (注意跟 <> 的区别),签名如下
-- file: PrettyJson.hs
hcat :: [Doc]-> Doc
hcat xs = undefined
接下来,由于map函数是对列表s的每个元素应用oneChar函数,故我们只要看一下oneChar函数是干什么用的就可以了。由于s是一个String类型,故oneChar函数是将一个Char类型转为一个Doc类型,给出函数的详细定义如下,
-- file: PrettyJson.hs
oneChar :: Char –> Doc
oneChar c = case lookup c simpleEscapes of
Just r –> text r
Nothing | mustEscape –> hexEscape c
| otherwise -> char c
where mustEscape c = c < ' ' || c == '\x7f' || c > '\xff'
simpleEscapes :: [(Char, String)]
simpleEscapes = zipWith ch "\b\n\f\r\t\\\"/" "bnfrt\\\"/"
where ch a b = (a, ['\\', b]
这段函数定义篇幅稍微有点大,我们一点一点来看,首先simpleEscapes是一个二元元组的列表,元组的第一项为一个简单转义字符(\b, \n, \f, \r, \t, \\, \", /),第二项是将第一项表现出来,比如 '\b' ,表现为 "\\b" ,可以写一个测试如下
Prelude> :load PrettyJson.hs
Prelude> take 8 simpleEscapes
[('\b',"\\b"),('\n',"\\n"),('\f',"\\f"),('\r',"\\r"),('\t',"\\t"),('\\',"\\\\"),('"',"\\\""),('/',"\\/")]
lookup函数是检查字符c是否在simpleEscapes中某一元组的第一项,如果是,则返回这个转义字符的字符串表现形式,如果字符c不是简单的转义字符,则如果是其他需要转义的字符,对字符c应用hexEscape函数,否则,就是简单的字符,不需要转义,直接应用char函数将Char类型转为Doc类型。
还有一个函数hexEscape还未给出解析。我们直接给出定义如下
-- file: PrettyJson.hs
hexEscape :: Char –> Doc
hexEscape c | d < 0x10000 = smallHex d
| otherwise = astral (d – 0x10000)
where d = ord c
根据字符c的ascii码值是否小于0x10000,对字符c的码值进行不同的处理。
-- file: PrettyJson.hs
smallHex :: Int –> Doc
smallHex x = text "\\u"
<> text (replicate (4 – length h) ‘0’)
<> text h
where h = showHex x ""
其中,showHex函数来自Numeric库,需要在文件的开头import这个库。showHex函数的功能是以16进制打印一个数。replicate函数是将一个指定类型a重复n次,生成一个a类型的列表
replicate :: Int –> a –> [a]
根据hexEscape的定义,字符c的ascii码值(16进制)的长度不超过4位(根据guard表达式为d< 0x10000得到),故4 – length h 的范围为[0, 4],smallHex函数的作用是这样打印参数x,先打印"\\u", 然后x的16进制位数如果不足4位,补0使得满足4位,然后打印x的16进制值。
smallHex函数能打印的值最大不超过0xffff,而有效的unicode字符范围上限一直到0x10ffff,对 (0xffff, 0x10ffff) 的字符,应用 astral 函数,其定义给出如下
-- file: PrettyJson.hs
astral :: Int –> Doc
astral n = smallHex (a + 0xd800) <> smallHex (b + 0xdc00)
where a = (n `shiftR` 10).&. 0x3ff
b = n .&. 0x3ff
其中,shiftR是右移函数,(.&.)是按位与。我们看一下astral函数是如何处理参数n的,对于参数n,取其低10位作为b,取其第11位到第20位(次低10位)作为a,当然了,前面说到参数的范围为 (0xffff, 0x10ffff) ,值位数就是17位到20位,故 a 是高10位,b 是低10位。
Haskell Json数据处理的更多相关文章
- 【多端应用开发系列1.1.1 —— Android:使用新浪API V2】服务器Json数据处理——Json数据概述
[前白] 一些基础的东西本系列中就不再详述了,争取尽量写些必不可少的技术要点. 由于本系列把Web Service 构建放到了第二部分,Android项目就采用新浪微博API v2作为服务器端. [原 ...
- iOS开发——数据解析Swift篇&简单json数据处理
简单json数据处理 //loadWeather var url = NSURL(string: "http://www.weather.com.cn/adat/sk/101240701.h ...
- Spark SQL JSON数据处理
背景 这一篇可以说是“Hive JSON数据处理的一点探索”的兄弟篇. 平台为了加速即席查询的分析效率,在我们的Hadoop集群上安装部署了Spark Server,并且与我们的Hive数据仓 ...
- python接口自动化(十九)--Json 数据处理---实战(详解)
简介 上一篇说了关于json数据处理,是为了断言方便,这篇就带各位小伙伴实战一下.首先捋一下思路,然后根据思路一步一步的去实现和实战,不要一开始就盲目的动手和无头苍蝇一样到处乱撞,撞得头破血流后而放弃 ...
- JSON数据处理框架Jackson精解第一篇-序列化与反序列化核心用法
Jackson是Spring Boot默认的JSON数据处理框架,但是其并不依赖于任何的Spring 库.有的小伙伴以为Jackson只能在Spring框架内使用,其实不是的,没有这种限制.它提供了很 ...
- ASP.MVC时间类型json数据处理
服务端返回DateTime属性如果用自带的json方法返回的数据如下: 有2种办法解决一种是采用服务端解决方案,一种是使用前端解决方案 1.前端解决方案 第一步:对Date进行扩展 // 对Date的 ...
- Qt json 数据处理
用到的头文件 #include <QJsonArray> #include <QJsonDocument> #include <QJsonObject> json解 ...
- json数据处理实战:Kafka+Flume+Morphline+Solr+Hue数据组合索引
背景:Kafka消息总线的建成,使各个系统的数据得以在kafka节点中汇聚,接下来面临的任务是最大化数据的价值,让数据“慧”说话. 环境准备: Kafka服务器*3. CDH 5.8.3服务器*3,安 ...
- Json数据处理
1.字符串转换为Json数组:取json对象属性值. String st="[{"tradeDate":"2016-09-27","trad ...
随机推荐
- Setting up Ubuntu in CoLinux–changing local/keyboard to be English
Today i installed the CoLinux with Ubuntu package, but the default locale setting of the system is G ...
- JS的基本概念
JS的基本概念 任何语言的核心都必然会描述这门语言最基本的工作原理.而描述的内容通常都要涉及这门语言的语法,操作符,数据类型,内置功能等用于构建复杂解决方案的概念.Ecma-262通过叫做EcmaSc ...
- 《Head First Python》学习笔记 01
Python 3提供了70多个内建函数,这是Python“功能齐全”的观点:Python已经包含足够多的内置功能,使你能完成大多数工作,而不必依赖第三方代码. Python 列表: Python列表是 ...
- icon 图标下载
1. http://www.easyicon.net/ 2.http://www.iconpng.com/
- POJ 2409 Let it Bead 组合数学
题目地址: http://poj.org/problem?id=2409 给你一串珠子有m个,用n种不同的颜色涂色,问有多少种分法. 用polay定理求解,对于排成一排的带编号的小球,按照某一种方案改 ...
- install cuda5 on ubuntu12.04
1. sudo apt-get install libglapi-mesa 2. sudo apt-get install freeglut3-dev build-essential libx11-d ...
- 关于EL表达式的生效时间(猜想)
通过ajax与服务端异步交互的时候,在服务端将某些变量或对象设置到request等域里,此时页面上的EL表达式是获取不到ajax异步交互时设置在request等域里的变量或对像的. 我猜测可能EL表达 ...
- Prefix the choice with ! to persist it to bower.json ? Answer (问你选择哪个1,2,3.........)
Unable to find a suitable version for underscore, please choose one by typing on e of the numbers be ...
- 【01背包】HDU 1171 Big Event in HDU
Problem Description Nowadays, we all know that Computer College is the biggest department in HDU. Bu ...
- html5之datalist标签
当我看到这个标签的时候,其实我是很愤怒的.因为我以前实现过这个标签的功能,当时是无比的费劲.什么js库呀,function呀.我靠,统统去屎吧,哥有datalist了.那种感觉就好像自己千辛万苦去追去 ...