1

我有包含两个数字的文件 txt,例如:

2.

3.

你怎么能看到,每一行的结尾都以点结尾。

我如何阅读并打印例如这些数字的总和?

如果我的文件不包含点,例如我有

2

3

这不是问题。我的代码是:

main3 = do
    x <- openFile "C:/Users/file.txt"  ReadMode
    m <- hGetLine x
    n <- hGetLine x
    return ((read m::Int)+(read n::Int))

而且效果很好。但是当我的文件中有点时,我不知道我能做什么。也许有任何图书馆?

感谢帮助。

4

3 回答 3

5

问题是它read不会解析"3."为 mean 3。如果您只是想以一种 hacky 的方式执行此操作,则可以删除最后一个字符。

main4 = do
    x <- openFile "C:/Users/file.txt"  ReadMode
    m <- hGetLine x
    n <- hGetLine x
    return ((read (init m)::Int)+(read (init n)::Int))

这可能有效但非常脆弱,因为它假定每行中唯一的非数字字符是最后一个。n我们可以通过假设第一个数字字符构成我们的数字来做得更好

import Data.Char

-- takeWhile isDigit :: String -> String

main5 path = do
  f <- readFile path
  numberStrings <- map (takeWhile isDigit) (lines f)
  sum (map read numberStrings)

最强大的解决方案是升级到像 Parsec 这样的“解析器组合库”,它可以让您写出文本文件的语法。

于 2013-06-25T12:51:37.120 回答
3

有几种方法可以做到这一点..最简单的是

main = do
  text <- readFile "file.txt" -- Grab the file
  let nums = map read . map init . lines $ text
  print $ sum nums

init只是丢掉.. 但是我会这样写

import Text.Parsec.String
import Text.Parsec
import Control.Applicative ((<*), (<$>))

getNums :: Parser [Int]
getNums = num `sepEndBy` newline
    where num = read <$> many1 digit <* char '.'

main = parseFromFile getNums "filename" >>= print . fmap sum

像这样的事情值得使用 parsec 吗?答案是“视情况而定”。我的经验法则是,如果我打算多次使用它,那就硬着头皮使用秒差。使用像 parsec 这样的库来修改新的和更复杂的格式要容易得多。另外,您可以通过这种方式获得免费的 [体面] 错误消息。

于 2013-06-25T12:51:51.730 回答
0

您可以利用 Haskell 的 monadic API 分几个步骤完成此操作:

  1. 每行读入文件行
  2. 检查每行是否以点结尾:使用map并返回一个Maybe monad:当行不以点结尾时为Nothing,当行以点结尾时Just(不带点的值)
  3. 使用 map + flatten 将每个字符串转换为数字,再次使用 Maybe monad。有错误时什么都没有,或者只是 x 包含数字
  4. 使用折叠对值求和

当我有时间时,我会尝试构建一个示例。使用 Haskell 的 monadic API 总是很有趣。

于 2013-06-25T12:56:58.250 回答