GHC / Haskell如何决定从哪个字符编码解码/编码?

时间:2011-03-13 01:44:43

标签: haskell character-encoding ghc

似乎GHC至少在它决定解码的字符编码中不一致。

考虑一个文件omatase-shimashita.txt,其中包含以UTF-8编码的以下内容:お待たせしました

readFile似乎正确地读了这个......

Prelude> content <- readFile "/home/chris/Desktop/omatase-shimashita.txt"
Prelude> length content
8
Prelude> putStrLn content
お待たせしました

但是,如果我编写一个简单的“echo”服务器,它不会使用默认的UTF-8进行解码。请考虑以下处理传入客户端的代码:

handleClient handle = do
  line <- hGetLine handle
  putStrLn $ "Read following line: " ++ toString line
  handleClient handle

相关客户端代码,明确发送UTF-8:

Data.ByteString.hPutStrLn handle $ Codec.Binary.UTF8.Generic.fromString "お待たせしました"

这不是不一致的行为吗?有这种疯狂的方法吗?我打算重写我的应用程序以显式使用ByteString个对象并使用Codec.Binary.UTF8显式编码和解码,但最好还是知道这里发生了什么......:o / < / p>

更新:我在Ubuntu Linux版本10.10上运行,其语言环境为en_US.UTF-8 ......

$ cat /etc/default/locale 
LANG="en_US.UTF-8"
$ echo $LANG 
en_US.UTF-8

2 个答案:

答案 0 :(得分:6)

您使用的是哪个版本的GHC?较旧的版本尤其不能很好地执行unicode I / O.

GHC文档中的这一部分描述了如何更改输入/输出编码:

http://haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/System-IO.html#23

此外,文档说明了这一点:

  

文本模式句柄具有关联   TextEncoding,用于解码   字节转换为Unicode字符时   读取和编码Unicode字符   写入时的字节数。

     

默认的TextEncoding是相同的   作为您的默认编码   系统,也可以作为   localeEncoding。 (GHC注意:在Windows上,   我们目前不支持   双字节编码;如果   控制台的代码页不受支持,   然后localeEncoding将是latin1。)

     

编码和解码错误   始终检测和报告,除了   在懒惰的I / O期间(hGetContents,   getContents和readFile),其中a   解码错误只会导致   终止字符流,   与其他I / O错误一样。

也许这与您的问题有关?如果GHC默认某个地方不是utf-8,或者你的句柄被手动设置为使用不同的编码,那么这可能解释了这个问题。如果你只是试图在控制台上回显文本,那么可能会出现某种控制台代码页的混乱。我知道我在过去使用其他语言(例如Python)和在Windows控制台中打印unicode时遇到了类似的问题。

尝试运行hSetEncoding handle utf8,看看它是否解决了您的问题。

答案 1 :(得分:6)

您的第一个示例使用标准IO库System.IO。除非另行指定,否则此库中的操作使用默认系统编码(也称为localeEncoding)。据推测,您的系统设置为使用UTF-8,因此putStrLnhGetContents等使用的编码就是这样。

您的第二个示例使用Data.ByteString。由于此库仅处理字节序列,因此不进行编码或解码。因此Data.ByteString.hGetLine将文件中的字节直接转换为ByteString

一般来说,执行文本I / O的最佳方法是使用text包。