在我的应用上工作时,我偶然发现了Aeson not decoding UTF8 input的问题。深入挖掘我发现它依赖于Attoparsec的Parser ByteString
,这对我来说似乎是问题的根源。但实际上并不是我在这里问的问题。
问题是我不是唯一一个看过人们使用ByteString
的地方,因为我觉得只有Text
是合适的,因为JSON不是一些二进制文件,它是一个可读的文本,它可能包含UTF8字符。
所以我想知道我是否遗漏了某些东西并且有正当理由选择ByteString
而不是Text
,或者这只是一个普遍存在的图书馆设计糟糕的现象,因为大多数人都缺少照顾关于除拉丁之外的任何其他角色集。
答案 0 :(得分:21)
我认为your problem只是一种误解。
Prelude> print "Ёжик лижет мёд."
"\1025\1078\1080\1082 \1083\1080\1078\1077\1090 \1084\1105\1076."
Prelude> putStrLn "\1025\1078\1080\1082 \1083\1080\1078\1077\1090 \1084\1105\1076."
Ёжик лижет мёд.
Prelude> "{\"a\": \"Ёжик лижет мёд.\"}"
"{\"a\": \"\1025\1078\1080\1082 \1083\1080\1078\1077\1090 \1084\1105\1076.\"}"
当您print
包含String
的值时,会使用Show
的{{1}}实例,并且会转义代码点数大于127的所有字符。你想要的字形,你需要Char
putStr[Ln]
。
所以String
正确解码了utf8编码的输入,应该是预期的,因为它对值本身进行了utf8编码:
aeson
所以问题为什么encode = {-# SCC "encode" #-} encodeUtf8 . toLazyText . fromValue .
{-# SCC "toJSON" #-} toJSON
使用aeson
而非ByteString
作为编码的最终目标和解码起点。
因为这是合适的类型。编码值旨在在机器之间移植。这发生在一个字节流(八位字节,如果我们处于迂腐的情绪)。这正是Text
所提供的,一系列字节,然后必须以特定于应用程序的方式处理。出于ByteString
的目的,字节流应以utf-8编码,aeson
假定aeson
函数的输入有效utf-8,并将其输出编码为有效的utf-8。
转移,例如decode
会遇到可移植性问题,因为16位编码取决于字节顺序,因此Text
不适合在机器之间交换数据。请注意,Text
在编码时使用aeson
作为中间类型(并且可能在解码时也是如此),因为这是在中间阶段使用的合适类型。
答案 1 :(得分:2)
JSON标准已经确定了UTF-16,而不是UTF-8。更多详细信息,请访问官方网站http://json.org/。 (为了进一步防御Aeson,JSON的二进制位不会通过其接口公开:String
的{{1}}构造函数包含Value
,而不是Text
。 )