haskell将unicode序列转换为utf 8

时间:2016-02-28 20:12:33

标签: haskell unicode utf-8

我正在使用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。看起来我的替换功能有错误,也许如果我修复它,它也将解决主要问题。

1 个答案:

答案 0 :(得分:1)

我不确定您是否属于“打印unicode”陷阱(请参阅here) - 对于en / decode,已存在hackage: Data.Text.Encoding decodeUtf8 :: ByteString -> TextencodeUtf8 :: 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”行。