【问题标题】:Filtering by length of lines in file giving unexpected result按文件中的行长过滤会产生意想不到的结果
【发布时间】:2018-12-10 23:10:50
【问题描述】:

我正在努力学习Learn You a Haskell,这对我很有好处。我目前在第 9 章的文件和流部分。出于某种原因,当我尝试将代码通过管道传输到一个示例 Haskell 程序中时,我没有得到与本书相同的输出。在 Windows 上使用 ConEmu for Linux 命令。例如,我的程序只打印出少于 10 个字符的字符串,代码如下(short_lines.hs):

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 编辑器中删除尾随换行符,但它没有改变任何东西。任何关于为什么我没有得到预期结果以及我可以做些什么来获得预期结果的帮助将不胜感激。谢谢!

【问题讨论】:

  • 很奇怪。检查尾随空格。检查' 是否为标准报价。尝试main = interact $ unlines . map (show . length) . lines 打印所有行的长度。
  • 当给定有问题的输入时,程序main = getContents &gt;&gt;= print的输出是什么?
  • 这真的很有帮助。我发现输出是"i'm short\r\nso am i\r\ni am a loooooooooong line!!!\r\nyeah i'm long so what hahahaha!!!!!!\r\nshort line\r\nloooooooooooooooooooooooooooong\r\nshort\r\n"。然后我做了一些搜索,发现了 Windows 回车与 Unix 的区别。谢谢!

标签: haskell io pipe


【解决方案1】:

标准输入的默认换行模式是nativeNewline,它根据它认为你的操作系统是什么来选择它的行为。我怀疑它(错误地)决定您使用的是 Unix 系统,因此它不应该进行 CRLF 转换;因此,当给定一个 Windows 风格的文件时,每一行都有一个尾随 '\r' 字符。尝试使用

import System.IO

main = do
  hSetNewlineMode stdin universalNewlineMode
  interact $ unlines . filter ((<10) . length) . lines

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

我可以在我的 Unix 系统上重现您的问题,方法是将文本文件转换为 DOS 模式,然后再将其提供给您的程序。这样做后,我建议的修复程序会获得所需的行为。

【讨论】:

    【解决方案2】:

    我发现我可以在 Atom 编辑器上将行尾样式从 Windows-CRLF 更改为 Unix-LF。目前它位于底部,简单地说是 CRLF 或 LF。您可以单击它来选择不同的线条样式。对于本书,为了简单起见,我将使用它。但是,我相信 amalloy 的答案是一种更好的长期通用的 IO 方法。

    【讨论】:

      猜你喜欢
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      • 2017-05-02
      • 2019-04-05
      • 1970-01-01
      • 2015-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多