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

Chr*_* W. 12 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
????????
Run Code Online (Sandbox Code Playgroud)

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

handleClient handle = do
  line <- hGetLine handle
  putStrLn $ "Read following line: " ++ toString line
  handleClient handle
Run Code Online (Sandbox Code Playgroud)

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

Data.ByteString.hPutStrLn handle $ Codec.Binary.UTF8.Generic.fromString "????????"
Run Code Online (Sandbox Code Playgroud)

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

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

$ cat /etc/default/locale 
LANG="en_US.UTF-8"
$ echo $LANG 
en_US.UTF-8
Run Code Online (Sandbox Code Playgroud)

chr*_*sdb 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

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

文本模式Handle具有关联的TextEncoding,用于在读取时将字节解码为Unicode字符,并在写入时将Unicode字符编码为字节.

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

始终检测并报告编码和解码错误,但在惰性I/O(hGetContents,getContents和readFile)期间除外,其中解码错误仅导致字符流的终止,与其他I/O错误一样.

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

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


Sim*_*low 6

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

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

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