【问题标题】:UTF-8 input/output in from Haskell in Windows来自 Windows 中 Haskell 的 UTF-8 输入/输出
【发布时间】:2021-06-29 21:24:04
【问题描述】:

下面的简单代码在带有 UTF-8 字符的 Windows 终端中无法正常工作,无论是来自 Prelude 还是来自 Data.Text.IO 的 getLine/putStrLn:

main = forever $ getLine >>= putStrLn

它在输入过程中回显 utf-8 字符,然后打印“?”代替 utf-8 字符;使用chcp 65001 切换编码会使它们变成空格。

我已按照this page 的建议下载了新终端并启用了 utf-8 支持,但没有任何效果。

This explanation 似乎相关,但那里提出的解决方案不起作用(代码也是如此)。

显然python有一个similar issue

是否有任何适用于 GHC 8.x 的库/解决方法?

请帮忙!

编辑:经过更多调查,问题也出在输入过程中 - 如果不是 putStrLn 我用 mapM_ (print . ord) s 打印字符代码,它们要么都是 63 而没有更改编码,要么是 chcp 65001 之后的 0。

hSetEncoding stdin utf8 没有帮助

【问题讨论】:

  • 您使用的是哪个 Windows 版本?
  • 是windows 10

标签: haskell utf-8 terminal console


【解决方案1】:

我找到了执行此操作的库:https://hackage.haskell.org/package/terminal

它不包括getLine(仅关键事件),但实现起来很简单:

import Control.Monad.IO.Class (liftIO)
import System.Exit (exitSuccess)
import System.Terminal as C

getTermLine :: MonadTerminal m => m String
getTermLine = getChars ""
  where
    getChars s = awaitEvent >>= processKey s
    processKey s = \case
      Right (KeyEvent key ms) -> case key of
        CharKey c
          | ms == mempty || ms == shiftKey -> do
            C.putChar c
            flush -- works without flush in Windows, but not in Mac
            getChars (c : s)
          | otherwise -> getChars s
        EnterKey -> do
          putLn
          flush
          pure $ reverse s
        BackspaceKey -> do
          moveCursorBackward 1
          eraseChars 1
          flush
          getChars $ if null s then s else tail s
        _ -> getChars s
      Left Interrupt -> liftIO exitSuccess
      _ -> getChars s

【讨论】:

    猜你喜欢
    • 2014-04-16
    • 2010-12-12
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 2013-10-11
    相关资源
    最近更新 更多