2015-06-23 92 views
6

我在Windows 7 64位上。 r n在Haskell中翻译为 r r n

我的程序需要从外部源检索一些文本(Utf8编码),用它做一些事情,然后将其保存到磁盘。原始文本使用“\ r \ n”序列来表示换行符(我很乐意保持这种方式)。

问题:当使用每个Data.Text.writeFile为 “\ r \ n” 序列似乎被译为 “\ r \ r \ n”,这是每一个 '\ n' 被翻译成“\ r \ n“,,即使在原始文本之前已经有'\ r'。我知道,在Windows操作系统上写入文件时,'\ n'应该翻译为“\ r \ n”,当前还没有以'\ r'开头,但将“\ r \ n”翻译为“\ r \ r \ n”似乎不正确。

使用ByteString.writeLine应用到文本的encodeUtf8版本的效果很好,但(没有额外的 “\ r” 插入 “\ r \ n” 个序列内)

一个简单的例子:

{-# LANGUAGE OverloadedStrings #-} 
import qualified Data.ByteString as B 
import qualified Data.Text as T 
import qualified Data.Text.IO as T (writeFile) 
import qualified Data.Text.Encoding as T (encodeUtf8) 

str = "Line 1 is here\r\nLine 2 is here\r\nLine 3 is here" :: T.Text 

main = do 
    B.writeFile "byt.bin" $ T.encodeUtf8 str 
    T.writeFile "txt.bin" str 

用十六进制编辑器查看此代码生成的每个文件,可以看到在通过T.writeFile行生成的文件中每个x0A前面添加的额外x0D。

B.writeFile: enter image description here

T.writeFile: enter image description here

我的问题:我做了什么错?有没有办法在Windows上使用T.writeFile,而不是将“\ r \ n”翻译成“\ r \ r \ n”?

+0

为什么不将文件加载到Unix风格'“\ n”' - 只有?这肯定会让你的程序变得更容易,而且输出也会以''\ r \ n“'出来。 – leftaroundabout

+0

@leftaroundabout:我没有讲完整个故事,但原始文本位于base64格式的文件中。我首先需要从文件中读取BytesStrings,将它们解码(使用Data.ByteString.Base64),然后将它们转换为Text(并且我可以开始操作它)。在那个阶段,我可以将所有“\ r \ n”替换为“\ n”。这是你的建议吗? – Janthelme

+0

我确实会这样建议。如果程序中的字符串中有Windows风格的行结尾,它可能会导致各种其他麻烦。 – leftaroundabout

回答

10

你的答案是the docs

与GHC 6.12,文本开头的I/O是利用系统或处理的当前区域和行结束约定执行。

鉴于您自己并未打开句柄,库似乎很可能以文本模式打开文件,导致操作系统翻译末尾字符。您可以改为使用openBinaryFile以二进制模式打开该文件,然后使用Data.Text.hPutStr来防止出现这种情况。

但是,处理编码的操作系统也可能不是您想要的。根据你的情况,像你使用ByteString一样明确地编码/解码字符串可能是更好的主意。

+1

谢谢。我确认解决方案openBinaryFile和hPutStr起作用。 – Janthelme