似乎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
答案 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,因此putStrLn
,hGetContents
等使用的编码就是这样。
您的第二个示例使用Data.ByteString
。由于此库仅处理字节序列,因此不进行编码或解码。因此Data.ByteString.hGetLine
将文件中的字节直接转换为ByteString
。
一般来说,执行文本I / O的最佳方法是使用text包。