- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在Windows下的Haskell中,使控制台I / O与Unicode字符一起使用似乎很困难。这是祸水的故事:
(初步。)甚至在考虑在Windows下的控制台中执行Unicode I / O之前,您需要确保使用的控制台字体可以呈现所需的字符。光栅字体(默认设置)具有无限差的覆盖范围(并且不允许复制粘贴它们不能代表的字符),而MS提供的truetype选项(consolas,lucida控制台)的覆盖范围不是很大(尽管这些将允许)复制/粘贴他们无法代表的字符)。您可以考虑安装DejaVu Sans Mono(按照here底部的说明进行操作;可能需要重新启动才能工作)。在进行排序之前,没有任何应用程序可以执行很多Unicode I / O。不只是Haskell。
完成此操作后,您会注意到某些应用程序将能够在Windows下执行控制台I / O。但是,使其正常工作仍然相当复杂。在Windows下,基本上有两种写入控制台的方法。 (以下内容适用于所有语言,而不仅限于Haskell;请放心,Haskell稍后会输入图片!)...
选项A是使用通常的c库样式基于字节的I / O函数;希望操作系统将根据某种编码来解释这些字节,从而可以对您想要的所有奇怪而奇妙的字符进行编码。例如,使用Mac OS X上的等效技术(标准系统编码通常为UTF8),效果很好。您发送utf8输出,就会看到漂亮的符号。
在Windows上,效果不佳。 Windows期望的默认编码通常不会是覆盖所有Unicode符号的编码。因此,如果您想以一种或另一种方式查看漂亮的符号,则需要更改编码。一种可能性是您的程序使用SetConsoleCP
win32命令。 (因此,您需要绑定到Win32库。)或者,如果您不想这样做,则可以期望程序的用户为您更改代码页(然后他们必须在调用chcp
命令之前他们运行您的程序)。
选项B是使用支持Unicode的win32控制台API命令,例如WriteConsoleW
。在这里,您将UTF16直接发送到Windows,这使它愉快地呈现出来:没有编码不匹配的危险,因为Windows始终期望具有这些功能的UTF16。
不幸的是,这些选项在Haskell中都无法很好地工作。首先,据我所知没有使用选项B的库,所以这并不容易。剩下选项A。如果您使用Haskell的I / O库(putStrLn
等),则库将执行此操作。在现代版本的Haskell中,它将仔细询问Windows当前代码页是什么,并以正确的编码输出您的字符串。这种方法有两个问题:
一个不是风头浪尖的,而是令人讨厌的。如上所述,默认编码几乎不会对所需字符进行编码:您是用户,需要更改为可编码。因此,您的用户需要在运行程序之前先chcp cp65001
(您可能会发现强制用户执行此操作很令人讨厌)。或者您需要绑定到SetConsoleCP
并在程序内部进行等效操作(然后使用hSetEncoding
,以便Haskell库将使用新的编码发送输出),这意味着您需要包装win32库的相关部分使它们具有Haskell可见性。
更严重的是,有一个bug in windows(分辨率:无法修复)导致出现bug in Haskell,这意味着如果您选择了cp65001之类的代码页,它可以覆盖所有Unicode,那么Haskell的I / O例程将故障和失败。因此,从本质上讲,即使您(或您的用户)将编码正确设置为涵盖所有出色的Unicode字符的某种编码,然后在告诉Haskell使用该编码输出内容时“正确执行”,您仍然会迷失方向。
上面列出的错误仍未解决,被列为低优先级;基本结论是,选项A(在我的上面的分类中)不可行,并且需要切换到选项B才能获得可靠的结果。目前尚不清楚要解决这个问题的时间表是什么,因为这似乎是一项艰巨的工作。
问题是:与此同时,任何人都可以提出一种解决方法,以允许Windows下Haskell中使用Unicode控制台I / O。
另请参见此python bug tracker database entry,解决Python 3中的相同问题(已提出修订,但尚未接受代码库)和this stackoverflow answer,提供了针对Python中此问题的解决方法(基于我的“选项B”分类)。
最佳答案
我以为我会回答自己的问题,并列出以下可能的答案,这是我目前正在做的事情。一个人做得更好的可能性很大,这就是为什么我要问这个问题!但是我认为将以下内容提供给人们是有意义的。基本上,这是python workaround for the same issue从Python到Haskell的翻译。它使用问题中提到的“选项B”。
基本思想是创建具有以下内容的模块IOUtil.hs,可以将其import
插入代码中:
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE NoImplicitPrelude #-}
module IOUtil (
IOUtil.interact,
IOUtil.putChar, IOUtil.putStr, IOUtil.putStrLn, IOUtil.print,
IOUtil.getChar, IOUtil.getLine, IOUtil.getContents, IOUtil.readIO,
IOUtil.readLn,
ePutChar, ePutStr, ePutStrLn, ePrint,
trace, traceIO
) where
#ifdef mingw32_HOST_OS
import System.Win32.Types (BOOL, HANDLE, DWORD, LPDWORD, LPWSTR, LPCWSTR, LPVOID)
import Foreign.C.Types (CWchar)
import Foreign
import Prelude hiding (getContents, putStr, putStrLn) --(IO, Read, Show, String)
--import qualified System.IO
import qualified System.IO (getContents)
import System.IO hiding (getContents, putStr, putStrLn)
import Data.Char (ord)
{- <http://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx>
HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
returns INVALID_HANDLE_VALUE, NULL, or a valid handle -}
foreign import stdcall unsafe "GetStdHandle" win32GetStdHandle :: DWORD -> IO (HANDLE)
std_OUTPUT_HANDLE = -11 :: DWORD -- all DWORD arithmetic is performed modulo 2^n
std_ERROR_HANDLE = -12 :: DWORD
{- <http://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx>
DWORD WINAPI GetFileType(HANDLE hFile); -}
foreign import stdcall unsafe "GetFileType" win32GetFileType :: HANDLE -> IO (DWORD)
_FILE_TYPE_CHAR = 0x0002 :: DWORD
_FILE_TYPE_REMOTE = 0x8000 :: DWORD
{- <http://msdn.microsoft.com/en-us/library/ms683167(VS.85).aspx>
BOOL WINAPI GetConsoleMode(HANDLE hConsole, LPDWORD lpMode); -}
foreign import stdcall unsafe "GetConsoleMode" win32GetConsoleMode :: HANDLE -> LPDWORD -> IO (BOOL)
_INVALID_HANDLE_VALUE = (intPtrToPtr $ -1) :: HANDLE
is_a_console :: HANDLE -> IO (Bool)
is_a_console handle
= if (handle == _INVALID_HANDLE_VALUE) then return False
else do ft <- win32GetFileType handle
if ((ft .&. complement _FILE_TYPE_REMOTE) /= _FILE_TYPE_CHAR) then return False
else do ptr <- malloc
cm <- win32GetConsoleMode handle ptr
free ptr
return cm
real_stdout :: IO (Bool)
real_stdout = is_a_console =<< win32GetStdHandle std_OUTPUT_HANDLE
real_stderr :: IO (Bool)
real_stderr = is_a_console =<< win32GetStdHandle std_ERROR_HANDLE
{- BOOL WINAPI WriteConsoleW(HANDLE hOutput, LPWSTR lpBuffer, DWORD nChars,
LPDWORD lpCharsWritten, LPVOID lpReserved); -}
foreign import stdcall unsafe "WriteConsoleW" win32WriteConsoleW
:: HANDLE -> LPWSTR -> DWORD -> LPDWORD -> LPVOID -> IO (BOOL)
data ConsoleInfo = ConsoleInfo Int (Ptr CWchar) (Ptr DWORD) HANDLE
writeConsole :: ConsoleInfo -> [Char] -> IO ()
writeConsole (ConsoleInfo bufsize buf written handle) string
= let fillbuf :: Int -> [Char] -> IO ()
fillbuf i [] = emptybuf buf i []
fillbuf i remain@(first:rest)
| i + 1 < bufsize && ordf <= 0xffff = do pokeElemOff buf i asWord
fillbuf (i+1) rest
| i + 1 < bufsize && ordf > 0xffff = do pokeElemOff buf i word1
pokeElemOff buf (i+1) word2
fillbuf (i+2) rest
| otherwise = emptybuf buf i remain
where ordf = ord first
asWord = fromInteger (toInteger ordf) :: CWchar
sub = ordf - 0x10000
word1' = ((shiftR sub 10) .&. 0x3ff) + 0xD800
word2' = (sub .&. 0x3FF) + 0xDC00
word1 = fromInteger . toInteger $ word1'
word2 = fromInteger . toInteger $ word2'
emptybuf :: (Ptr CWchar) -> Int -> [Char] -> IO ()
emptybuf _ 0 [] = return ()
emptybuf _ 0 remain = fillbuf 0 remain
emptybuf ptr nLeft remain
= do let nLeft' = fromInteger . toInteger $ nLeft
ret <- win32WriteConsoleW handle ptr nLeft' written nullPtr
nWritten <- peek written
let nWritten' = fromInteger . toInteger $ nWritten
if ret && (nWritten > 0)
then emptybuf (ptr `plusPtr` (nWritten' * szWChar)) (nLeft - nWritten') remain
else fail "WriteConsoleW failed.\n"
in fillbuf 0 string
szWChar = sizeOf (0 :: CWchar)
makeConsoleInfo :: DWORD -> Handle -> IO (Either ConsoleInfo Handle)
makeConsoleInfo nStdHandle fallback
= do handle <- win32GetStdHandle nStdHandle
is_console <- is_a_console handle
let bufsize = 10000
if not is_console then return $ Right fallback
else do buf <- mallocBytes (szWChar * bufsize)
written <- malloc
return . Left $ ConsoleInfo bufsize buf written handle
{-# NOINLINE stdoutConsoleInfo #-}
stdoutConsoleInfo :: Either ConsoleInfo Handle
stdoutConsoleInfo = unsafePerformIO $ makeConsoleInfo std_OUTPUT_HANDLE stdout
{-# NOINLINE stderrConsoleInfo #-}
stderrConsoleInfo :: Either ConsoleInfo Handle
stderrConsoleInfo = unsafePerformIO $ makeConsoleInfo std_ERROR_HANDLE stderr
interact :: (String -> String) -> IO ()
interact f = do s <- getContents
putStr (f s)
conPutChar ci = writeConsole ci . replicate 1
conPutStr = writeConsole
conPutStrLn ci = writeConsole ci . ( ++ "\n")
putChar :: Char -> IO ()
putChar = (either conPutChar hPutChar ) stdoutConsoleInfo
putStr :: String -> IO ()
putStr = (either conPutStr hPutStr ) stdoutConsoleInfo
putStrLn :: String -> IO ()
putStrLn = (either conPutStrLn hPutStrLn) stdoutConsoleInfo
print :: Show a => a -> IO ()
print = putStrLn . show
getChar = System.IO.getChar
getLine = System.IO.getLine
getContents = System.IO.getContents
readIO :: Read a => String -> IO a
readIO = System.IO.readIO
readLn :: Read a => IO a
readLn = System.IO.readLn
ePutChar :: Char -> IO ()
ePutChar = (either conPutChar hPutChar ) stderrConsoleInfo
ePutStr :: String -> IO ()
ePutStr = (either conPutStr hPutStr ) stderrConsoleInfo
ePutStrLn :: String -> IO ()
ePutStrLn = (either conPutStrLn hPutStrLn) stderrConsoleInfo
ePrint :: Show a => a -> IO ()
ePrint = ePutStrLn . show
#else
import qualified System.IO
import Prelude (IO, Read, Show, String)
interact = System.IO.interact
putChar = System.IO.putChar
putStr = System.IO.putStr
putStrLn = System.IO.putStrLn
getChar = System.IO.getChar
getLine = System.IO.getLine
getContents = System.IO.getContents
ePutChar = System.IO.hPutChar System.IO.stderr
ePutStr = System.IO.hPutStr System.IO.stderr
ePutStrLn = System.IO.hPutStrLn System.IO.stderr
print :: Show a => a -> IO ()
print = System.IO.print
readIO :: Read a => String -> IO a
readIO = System.IO.readIO
readLn :: Read a => IO a
readLn = System.IO.readLn
ePrint :: Show a => a -> IO ()
ePrint = System.IO.hPrint System.IO.stderr
#endif
trace :: String -> a -> a
trace string expr = unsafePerformIO $ do
traceIO string
return expr
traceIO :: String -> IO ()
traceIO = ePutStrLn
WriteConsoleW
(可识别Unicode的win32控制台函数)直接写到win32控制台。在非Windows平台上,条件编译意味着此处的函数仅称为标准库函数。
ePutStrLn
,而不是
hPutStrLn stderr
;我们没有定义
hPutStrLn
。 (定义一个是读者的练习!)
关于windows - Windows上Haskell中的Unicode控制台I/O,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25656809/
在使用 requests 库中的状态代码时,我遇到了一些奇怪的事情。每个 HTTP 状态代码都有一个常量,有些具有别名(例如,包括 200 的复选标记): url = 'https://httpbin
这是我得到的代码,但我不知道这两行是什么意思: o[arr[i]] = o[arr[i]] || {}; o = o[arr[i]]; 完整代码: var GLOBAL={}; GLOBAL.name
所以这个问题的答案What is the difference between Θ(n) and O(n)? 指出“基本上,当我们说算法是 O(n) 时,它也是 O(n2)、O(n1000000)、O
这是一个快速的想法;有人会说 O(∞) 实际上是 O(1) 吗? 我的意思是它不依赖于输入大小? 所以在某种程度上它是恒定的,尽管它是无限的。 或者是唯一“正确”的表达方式 O(∞)? 最佳答案 无穷
这是真的: log(A) + log(B) = log(A * B) [0] 这也是真的吗? O(log(A)) + O(log(B)) = O(log(A * B)) [1] 据我了解 O(f
我正在解决面试练习的问题,但我似乎无法找出以下问题的时间和空间复杂度的答案: Given two sorted Linked Lists, merge them into a third list i
我了解 Big-Oh 表示法。但是我该如何解释 O(O(f(n))) 是什么意思呢?是指增长率的增长率吗? 最佳答案 x = O(n)基本上意味着 x <= kn对于一些常量 k . 因此 x = O
我正在编写一个函数,该函数需要一个对象和一个投影来了解它必须在哪个字段上工作。 我想知道是否应该使用这样的字符串: const o = { a: 'Hello There' }; funct
直觉上,我认为这三个表达式是等价的。 例如,如果一个算法在 O(nlogn) + O(n) 或 O(nlogn + n) 中运行(我很困惑),我可以假设这是一个O(nlogn) 算法? 什么是真相?
根据 O'Reilly 的 Python in a Nutshell 中的 Alex Martelli,复杂度类 O(n) + O(n) = O(n)。所以我相信。但是我很困惑。他解释说:“N 的两个
O(n^2)有什么区别和 O(n.log(n)) ? 最佳答案 n^2 的复杂性增长得更快。 关于big-o - 大 O 符号 : differences between O(n^2) and O(n
每当我收到来自 MS outlook 的电子邮件时,我都会收到此标记 & nbsp ; (没有空格)哪个显示为?在 <>. 当我将其更改为 ISO-8859-1 时,浏览器页面字符集编码为 UTF-8
我很难理解 Algorithms by S. Dasgupta, C.H. Papadimitriou, and U.V. Vazirani - page 24 中的以下陈述它们将 O(n) 的总和表
我在面试蛋糕上练习了一些问题,并在问题 2给出的解决方案使用两个单独的 for 循环(非嵌套),解决方案提供者声称他/她在 O(n) 时间内解决了它。据我了解,这将是 O(2n) 时间。是我想错了吗,
关于 Java 语法的幼稚问题。什么 T accept(ObjectVisitorEx visitor); 是什么意思? C# 的等价物是什么? 最佳答案 在 C# 中它可能是: O Accept(
假设我有一个长度为 n 的数组,我使用时间为 nlogn 的排序算法对它进行了排序。得到这个排序后的数组后,我遍历它以找到任何具有线性时间的重复元素。我的理解是,由于操作是分开发生的,所以时间是 O(
总和 O(1)+O(2)+ .... +O(n) 的计算结果是什么? 我在某处看到它的解决方案: O(n(n+1) / 2) = O(n^2) 但我对此并不满意,因为 O(1) = O(2) = co
这个问题在这里已经有了答案: 11 年前关闭。 Possible Duplicate: Plain english explanation of Big O 我想这可能是类里面教的东西,但作为一个自学
假设我有两种算法: for (int i = 0; i 2)更长的时间给定的一些n - 其中n这种情况的发生实际上取决于所涉及的算法 - 对于您的具体示例, n 2)分别时间,您可能会看到: Θ(n)
这个问题在这里已经有了答案: Example of a factorial time algorithm O( n! ) (4 个回答) 6年前关闭。 我见过表示为 O(X!) 的 big-o 示例但
我是一名优秀的程序员,十分优秀!