问题 尝试打印Unicode字符时出现运行时异常


Char 是Haskell中Unicode字符的类型,和 String 很简单 [Char] (即一份清单 Char 项目)。这是一些简单的代码:

main = putStrLn "" -- Unicode string

这段代码编译得很好,但是当我在运行它时,我得到了运行时异常 PowerShel.exe 要么 CMD.EXE

app.exe :: commitBuffer:无效参数(无效字符)

为什么会这样?奇怪的是,当我在C#中做同样的事情时,我也不例外:

Console.WriteLine("");

在.NET中,字符也是Unicode。 电源外壳 要么 CMD 版画 c 代替 ,但至少我不例外。如何让Haskell可执行文件顺利运行?


12476
2017-12-23 08:25


起源

可能是Haskell要求程序在unicode shell中运行。 - Bartek Banachewicz
我的cmd shell打印出来 "©" 很好,但扼杀相同的错误 "ഠഃ അ ഠൃ ൩"。 - chi
可能有用: stackoverflow.com/questions/22349139/... 我不是PowerShell或C#专家,但是在运行C#程序时发生某些字符替换(“c”而不是“©”)的事实可能表明PowerShell未设置为使用UTF-8 ... @ chi Unicode字符串在Mac OS X上打印得很好;我通过终端使用bash,它设置为使用UTF-8。 - jubobs
@Jubobs确实,在linux上终端也设置为UTF-8,我从来没有遇到过问题。 @Bush如果你想要的只是避免异常,你可以使用 chcp 65001 在终端 - 所有非ascii字符将是不可读的。 - chi
@Bush您是否使用了设置代码页 chcp.com 65001? - bheklilr


答案:


我认为这应该算作GHC中的一个错误,但有一个解决方法。 GHC程序中所有句柄的默认编码(在二进制模式下打开的除外)只是控制台接受的编码,没有错误处理。幸运的是,你可以添加这样的错误处理。

makeSafe h = do
  ce' <- hGetEncoding h
  case ce' of
    Nothing -> return ()
    Just ce -> mkTextEncoding ((takeWhile (/= '/') $ show ce) ++ "//TRANSLIT") >>=
      hSetEncoding h

main = do
  mapM_ makeSafe [stdout, stdin, stderr]
  -- The rest of your main function.

3
2017-12-26 01:57



谢谢。我现在也不例外,但我仍然和我的预期不一样。我有 <interactive>. ? First Second, 2014 输出而不是 © First Second, 2014。 - Andrey Bushman
它正在添加“?”因为您的控制台使用的编码没有“©”字符,但我以前从未见过添加“<interactive>”,我不知道那里发生了什么。您还可以将此答案与@ bheklilr的答案结合起来,将您的控制台编码更改为具有您需要的字符的内容(代码页65001使用与utf-8相同的方法来记录字符大小,但不幸的是,它只能被称为utf-8,如果你不关心实际显示的是什么字符) - Jeremy List
该 <interactive>. 我加载代码时存在 ghci中 并运行 main 手动功能。如果我将我的代码编译为exe文件,我没有`<interactive>文本。谢谢。 - Andrey Bushman


在Windows上,修复是告诉shell使用 代码页65001 (这里的说明),将Windows置于“UTF-8模式”。它并不完美,但对于大多数角色,你应该看到unicode角色处理得更好。


7
2017-12-23 14:29



问题的另一半是“为什么GHC二进制崩溃而不是优雅地回退到像.NET二进制文件那样的非Unicode输出?” GHC可以 弄清楚系统区域设置;理论上我们应该能够进行编码转换并避免崩溃。我想知道是否有人调查过。 - Christian Conkle