我正在使用haskell中的http客户端(这是我的第一个“非exersize”项目)。
有一个api使用unicode返回带有所有文本的json,类似于
\u041e\u043d\u0430 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u0432\u0430\u0441 \u0432 \u0434\u043b\u0438\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a
我想将这个json解码为utf-8,从json消息中打印一些数据。
我搜索了现有的库,但为此找不到任何东西。
所以我编写了转换数据的函数(我使用了懒惰的字节串,因为我从wreq lib获得了这种类型的数据)
ununicode :: BL.ByteString -> BL.ByteString
ununicode s = replace s where
replace :: BL.ByteString -> BL.ByteString
replace str = case (Map.lookup (BL.take 6 str) table) of
(Just x) -> BL.append x (replace $ BL.drop 6 str)
(Nothing) -> BL.cons (BL.head str) (replace $ BL.tail str)
table = Map.fromList $ zip letters rus
rus = ["Ё", "ё", "А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "Й", "К", "Л", "М",
"Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ы",
"Ь", "Э", "Ю", "Я", "а", "б", "в", "г", "д", "е", "ж", "з", "и", "й", "к",
"л", "м", "н", "о", "п", "р", "с", "т", "у", "ф", "х", "ц", "ч", "ш", "щ",
"ъ", "ы", "ь", "э", "ю", "я"]
letters = ["\\u0401", "\\u0451", "\\u0410", "\\u0411", "\\u0412", "\\u0413",
"\\u0414", "\\u0415", "\\u0416", "\\u0417", "\\u0418", "\\u0419",
"\\u041a", "\\u041b", "\\u041c", "\\u041d", "\\u041e", "\\u041f",
"\\u0420", "\\u0421", "\\u0422", "\\u0423", "\\u0424", "\\u0425",
"\\u0426", "\\u0427", "\\u0428", "\\u0429", "\\u042a", "\\u042b",
"\\u042c", "\\u042d", "\\u042e", "\\u042f", "\\u0430", "\\u0431",
"\\u0432", "\\u0433", "\\u0434", "\\u0435", "\\u0436", "\\u0437",
"\\u0438", "\\u0439", "\\u043a", "\\u043b", "\\u043c", "\\u043d",
"\\u043e", "\\u043f", "\\u0440", "\\u0441", "\\u0442", "\\u0443",
"\\u0444", "\\u0445", "\\u0446", "\\u0447", "\\u0448", "\\u0449",
"\\u044a", "\\u044b", "\\u044c", "\\u044d", "\\u044e", "\\u044f"]
但它没有像我预期的那样奏效。它取代了文字,但我没有像cyrrilic字母那样的东西 345≤C1; 8:C5&lt; 8 = B5 @ 2LN A 4 = 52 = 8:> 2F0 <8 8 = B5 @ 5A = KE?@> D5AA89 8 E> 118
我无法调试我的功能的第二个问题。
当我尝试用自定义字符串调用它时出现错误Data.ByteString.Lazy.head: empty ByteString
我不知道为什么它是空的。
在正常的程序执行期间工作正常:
umailGet env params = do
r <- apiGet env (("method", "umail.get"):params)
x <- return $ case r of
(Right a) -> a
(Left a) -> ""
return $ ununicode $ x
而不是Main
r2 <- umailGet client []
print $ r2
最后一个问题是所有api都可以返回任何unicode符号,所以这个解决方案很糟糕。
当然函数实现似乎不好,所以在解决了主要问题之后,我将使用foldr重写它。
更新: 似乎我已经解决了问题不够明确。
所以我通过wreq lib发送请求,并获得json答案。例如
{"result":"12","error":"\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0441\u0441\u0438\u0438"}
这不是haskell表示结果的结果,而是真实的ascii符号。我使用curl或firefox获得相同的文本。 190字节/ 190 ascii符号。
使用此网站例如http://unicode.online-toolz.com/tools/text-unicode-entities-convertor.php我可以将其转换为cyrrilic text {"result":"12","error":"Неверный идентификатор сессии"}
我需要使用haskell实现类似这个服务的东西(或找到已经实现的包),其中像这样的响应类型为Lazy Bytestring。
我还尝试更改类型以使用Text而不是ByteString(Lazy和strict),将第一行更改为ununicode s = encodeUtf8 $ replace $ L.toStrict $ LE.decodeUtf8 s
使用这个新实现,我在执行程序时遇到错误
Data.Text.Internal.Fusion.Common.head: Empty stream
。看起来我的替换功能有错误,也许如果我修复它,它也将解决主要问题。
答案 0 :(得分:1)
我不确定您是否属于“打印unicode”陷阱(请参阅here) - 对于en / decode,已存在hackage: Data.Text.Encoding decodeUtf8 :: ByteString -> Text
和encodeUtf8 :: Text -> ByteString
应该完成任务。
我用text / bytestring玩了一段时间来重现你的“\ u1234”字符 - 好吧我不能
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.Text (Text)
import qualified Data.Text.Encoding as E
import qualified Data.Text.IO as T
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as B
inputB :: ByteString
inputB = "ДЕЖЗИЙКЛМНОПРСТУФ"
inputT :: Text
inputT = "ДЕЖЗИЙКЛМНОПРСТУФ"
main :: IO ()
main = do putStr "T.putStrLn inputT: " ; T.putStrLn inputT
putStr "B.putStrLn inputB: " ; B.putStrLn inputB
putStr "print inputB: " ; print inputB
putStr "print inputT: " ; print inputT
putStr "B.putStrLn $ E.encodeUtf8 inputT: " ; B.putStrLn $ E.encodeUtf8 inputT
putStr "T.putStrLn $ E.decodeUtf8 inputB: " ; T.putStrLn $ E.decodeUtf8 inputB
putStr "print $ E.decodeUtf8 inputB: " ; print $ E.decodeUtf8 inputB
putStr "print $ E.encodeUtf8 inputT: " ; print $ E.encodeUtf8 inputT
这是结果:
T.putStrLn inputT: ДЕЖЗИЙКЛМНОПРСТУФ
B.putStrLn inputB:
rint inputB: "\DC4\NAK\SYN\ETB\CAN\EM\SUB\ESC\FS\GS\RS\US !\"#$"
print inputT: "\1044\1045\1046\1047\1048\1049\1050\1051\1052\1053\1054\1055\1056\1057\1058\1059\1060"
B.putStrLn $ E.encodeUtf8 inputT: ДЕЖЗИЙКЛМНОПРСТУФ
T.putStrLn $ E.decodeUtf8 inputB:
rint $ E.decodeUtf8 inputB: "\DC4\NAK\SYN\ETB\CAN\EM\SUB\ESC\FS\GS\RS\US !\"#$"
print $ E.encodeUtf8 inputT: "\208\148\208\149\208\150\208\151\208\152\208\153\208\154\208\155\208\156\208\157\208\158\208\159\208\160\208\161\208\162\208\163\208\164"
老实说,我不知道为什么我在没有结果的字节串打印行之后得到“rint”行。