按文件中的行长过滤,得到意外结果

时间:2018-12-10 23:10:51

标签: haskell io pipe

我正在通过学​​习Haskell的方式努力工作。我目前正在第9章的“文件和流”部分中。由于某种原因,当我尝试将代码传递到示例Haskell程序之一中时,没有得到与本书相同的输出。在Windows上使用ConEmu for Linux命令。例如,我有一个程序仅使用以下代码(short_lines.hs)打印出少于10个字符的字符串:

main = interact $ unlines . filter ((<10) . length) . lines

我要传递此文件(short_long.txt):

i'm short
so am i
i am a loooooooooong line!!!
yeah i'm long so what hahahaha!!!!!!
short line
loooooooooooooooooooooooooooong
short

以下是命令:

cat short_long.txt | runhaskell short_lines.hs

这是我的输出:

so am i
short

这本书说输出如下:

i'm short  
so am i  
short 

我相信这与换行符的处理有关,但是我无法弄清楚这一点,因为行在过滤之前应该已经删除了换行符。它适用于手动输入,但不适用于管道。为什么我得到不同的输出?难道我做错了什么?我尝试在Atom编辑器中删除结尾的换行符,但没有任何改变。对于为什么我没有得到预期结果以及我能做些什么来获得预期结果的任何帮助,将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:3)

stdin的默认换行模式是nativeNewline,它根据其认为的操作系统来选择其行为。我怀疑它(错误地)确定您使用的是Unix系统,因此不应进行CRLF转换。因此,当给定Windows样式的文件时,每行都有一个结尾的Unit字符。尝试使用

'\r'

强制CRLF转换,看看是否能获得预期的结果。

我可以通过在将文本文件提供给程序之前将文本文件转换为DOS模式来在Unix系统上重现您的问题。这样做后,我建议的修复程序将获得所需的行为。

答案 1 :(得分:1)

我发现可以在Atom编辑器上将行结束样式从Windows-CRLF更改为Unix-LF。当前它位于底部,仅表示CRLF或LF。您可以单击它以选择其他线条样式。在本书中,为简单起见,这就是我将要使用的内容。但是,我相信amalloy的答案是对IO更好的长期通用方法。