在aeson中,您如何编码而不会产生科学记数法?

时间:2016-09-07 17:02:53

标签: haskell aeson

我已经解析了大量的json,操纵了一些值,我想把它写回来。 Aeson将数字解码为科学,但是当它编码时,默认情况下,科学在许多情况下以科学记数法显示数字,而且aeson没有提供任何我可以看到的改变它的方法。

> decode "[\"asdf\", 1, 1.0, 1000000000.1, 0.01]" :: Maybe Value
Just (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])

encode (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])
"[\"asdf\",1,1,1.0000000001e9,1.0e-2]"

> encode (Array [String "asdf", Number 1, Number 1.0, Number 1000000000.1, Number 0.01])
"[\"asdf\",1,1,1.0000000001e9,1.0e-2]"

如何用更广泛接受的格式用其他语言可以使用的数字写出我的值?让我们假装我不关心精度损失或整数溢出。科学软件包具有以这种方式格式化数字的方法,aeson恰好没有使用它。

>formatScientific Fixed Nothing (0.01)
"0.01"

>formatScientific Fixed Nothing (1000000000.1)
"1000000000.1"

2 个答案:

答案 0 :(得分:4)

pretty printer for Aeson(仅限0.8版本,非常近期)有一个配置选项,可以完全满足您的要求:

Prelude> :m +Data.Aeson Data.Aeson.Encode.Pretty 
Prelude Data.Aeson Data.Aeson.Encode.Pretty> encodePretty' (defConfig{confNumFormat=Decimal}) (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])
"[\n    \"asdf\",\n    1.0,\n    1.0,\n    1000000000.1,\n    0.01\n]"

不幸的是,这台漂亮的打印机现在将实际的整数输出为1.0而不是1,我认为这比用科学计数法打印小数要严重得多(这在任何地方都应该是正常的) )。使用默认设置也会发生这种情况:

Prelude Data.Aeson Data.Aeson.Encode.Pretty> encodePretty (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])
"[\n    \"asdf\",\n    1.0,\n    1.0,\n    1.0000000001e9,\n    1.0e-2\n]"

版本0.7.2仍然打印整数而没有小数部分,就像正常的aeson encode那样:

aeson-pretty-0.7.2:Data.Aeson.Encode.Pretty> encodePretty (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])
"[\n    \"asdf\",\n    1,\n    1,\n    1.0000000001e9,\n    1.0e-2\n]"

我想我会将此作为错误报告提交。

请注意,还有一个Custom NumberFormat选项,可让您完全控制数字的显示方式。

答案 1 :(得分:1)

我在自己面前寻找过这个功能;我相信那时我正在尝试与Ruby程序接口,而标准的Ruby JSON解析器并不支持科学记数法。不幸的是,我相信aeson无法做到这一点,所以你需要修补aeson或编写自己的编码器。

还有更多细节on the aeson issue tracker。该问题还建议在toEncoding以外的类型上使用Value来实现此目的,但不清楚这是否适用于您的情况。