Haskell中带有非英文字符的IO

5

看这里,我正在尝试

appendFile "out" $ show 'д'

“д”是俄语字母表中的一个字母。之后,“out”文件包含:
'\1076'

我理解的是字符“д”的Unicode数值代码。为什么会出现这种情况?我该如何得到我的字符的正常表示方式?
附加信息:它能够良好地工作。
appendFile "out"  "д"

谢谢。
6个回答

4

show会转义ASCII范围外(和一些ASCII范围内)的所有字符,所以不要使用show

由于"д"可以正常工作,因此只需使用它。如果您不能使用它,因为д实际上在变量内部,您可以使用[c](其中c是包含字符的变量)。如果您需要用单引号(就像show一样)将其括起来,则可以使用['\'', c, '\'']


6
许多Haskell程序员过度使用show,我认为这不适合用于漂亮的打印输出,因为它是用于序列化的(例如read . show应该等同于id),但大多数序列化应用程序的性能太差。它对于测试和原型设计很方便,但除此之外,我会三思而后再使用show - John L
我想使用“show”进行调试。“show”可以将“数据结构”转换为字符串。例如,我有[(String,String)],我希望看到它。当然,最好的输出方式是控制台输出,但这不可能。因为我使用文件。 - Anton
我同意调试是show命令最常见的好用途之一。但对于像你这样的情况,由于ASCII之外的转义字符(以及转义换行符,这对我来说特别烦人),它变得棘手起来。 - John L

3
阅读了您对我的评论的回复后,我认为您的情况是有一些数据结构,可能带有类型[(String,String)],并且您想要将其输出以进行调试。使用show会很方便,但它会转义非ASCII字符。
问题不在于Unicode,而在于需要一个能够正确格式化数据以供显示的函数。我认为选择show不是正确的选择,部分原因是因为转义某些字符的问题。你需要一个类似于Show的类型类,但它显示数据用于阅读而不是转义字符。也就是说,你需要一个漂亮的打印机,它是一个库,提供了函数来格式化数据以供显示。Hackage上有几个漂亮的打印机可供选择,我建议看看uulibwl-pprint。我认为任何一个都可以适用,而且不需要太多的工作。
这里有一个使用uulib工具的例子。使用Pretty类型类代替Show,该库带有许多有用的实例。
import UU.PPrint

-- | Write each item to StdOut
logger :: Pretty a => a -> IO ()
logger x = putDoc $ pretty x <+> line

在ghci中运行此命令:
Prelude UU.PPrint> logger 'Д'
Д 
Prelude UU.PPrint> logger ('Д', "other text", 54)
(Д,other text,54) 
Prelude UU.PPrint> 

如果你想将输出写入文件而非控制台,你可以使用 hPutDoc 函数将其输出到句柄。你也可以调用 renderSimple 生成一个 SimpleDoc,然后在构造函数上进行模式匹配以处理输出,但这可能会更麻烦。无论你做什么,都要避免使用 show
Prelude UU.PPrint> show $ pretty 'Д'
"\1044"

你也可以编写自己的类型类,类似于 show 但格式可以按照你的意愿进行调整。如果你选择这种方式,Text.Printf 模块可能会有所帮助。

你能给我一些关于漂亮打印机如何帮助我的技巧吗? - Anton
我已经添加了一个例子,应该可以让这个问题变得清晰明了。请注意,通常使用漂亮打印机的方式是一次性地组装所有数据并一次性呈现文档。我逐行执行此操作,因为这对于调试更有用;如果程序崩溃或挂起,您将获得更多的部分输出。 - John L

2
使用 Data.Text。它提供具有区域设置感知和编码支持的 IO。

2
Data.Text很棒,但内置的IO系统也提供了区域感知和编码支持(自GHC 6.12以来)。 - Simon Marlow

0

要显示国际字符,请在你的程序代码中添加:

{-# LANGUAGE FlexibleInstances #-}

instance {-# OVERLAPPING #-} Show String where
    show = id

你可以尝试一下:

*Main> show "ł"
ł
*Main> show "ą"
ą
*Main> show "ę"
ę
*Main> show ['ę']
ę
*Main> show ["chleb", "masło"]
[chleb,masło]
*Main> data T = T String deriving (Show)
*Main> t = T "Chleb z masłem"
*Main> t
T Chleb z masłem
*Main> show t
T Chleb z masłem

0

在我的先前解决方案中没有引号。此外,我现在将代码放入了模块中,该模块必须被导入到您的程序中。

{-# LANGUAGE FlexibleInstances #-}

module M where

instance {-# OVERLAPPING #-} Show String where
    show x = ['"'] ++ x ++ ['"']

初学者须知:记住,show 命令不会显示任何内容。它将数据转换为字符串,并添加格式化字符。

我们可以在 WinGHCi 中尝试: 通过 WinGHCi 自动执行

*M> "ł"
"ł"
*M> "ą"
"ą"
*M> "ę"
"ę"
*M> ['ę']
"ę"
*M> ["chleb", "masło"]
["chleb","masło"]
*M> data T = T String deriving (Show)
*M> t = T "Chleb z masłem"

或者手动

*M> (putStrLn . show) "ł"
"ł"
*M> (putStrLn . show) "ą"
"ą"
*M> (putStrLn . show) "ę"
"ę"
*M> (putStrLn . show) ['ę']
"ę"
*M> (putStrLn . show) ["chleb", "masło"]
["chleb","masło"]
*M> data T = T String deriving (Show)
*M> t = T "Chleb z masłem"
*M> (putStrLn . show) t
T "Chleb z masłem"

在代码中显示:

putStrLn "ł"
putStrLn "ą"
putStrLn "ę"
putStrLn "masło"
(putStrLn . show) ['ę']
(putStrLn . show) ["chleb", "masło"]
data T = T String deriving (Show)
t = T "Chleb z masłem"
(putStrLn . show) t

我正在为谷歌添加“polskie znaki haskell”标签。

代码 T 中的最后一行“Chleb z masłem”是错误的。请勿使用它。 - Egon

0
一次快速的网络搜索关于"UTF Haskell"的信息,会给你提供很多有用的链接。也许最推荐的包是text包。
import Data.Text.IO as UTF
import Data.Text as T

main = UTF.appendFile "out"  (T.pack "д")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接