逐行搜索.txt文件Haskell

时间:2018-03-13 12:54:30

标签: haskell

我是Haskell的新手,我创建了一个允许“用户”将新电影添加到数据库(一个名为Films.txt的文本文件)的函数。

main = do
    putStrLn "Insert film title:"
    film <- getLine
    putStrLn ("Who directed " ++ film ++ "?")
    director <- getLine
    putStrLn ("What year was " ++ film ++ " released?")
    year <- getLine
    appendFile "Films.txt" $ (film ++ "\n")
    appendFile "Films.txt" $ (director ++ "\n")
    appendFile "Films.txt" $ (year ++ "\n")
    appendFile "Films.txt" $ (" " ++ "\n")

创建的文本文件的示例是:

Blade Runner
Ridley Scott
1982
The Fly
David Cronenberg
1986
etc...

如果我想只返回某位导演的电影,我将如何逐行搜索此文件。在另一种语言中,我将使用FOR循环逐行搜索.txt文件,直到与搜索词匹配的行为例如“雷德利斯科特”。然后我将返回匹配行上方的行,输出它(电影名称)并继续搜索直到.txt文件完成。

然而在Haskell中,我无法将这个思维过程转换为代码,主要是因为我找不到逐行搜索文件的方法。

由于

1 个答案:

答案 0 :(得分:6)

使用您自己的方法,扫描文件以查找名称:

main = do
    putStrLn "Enter Director's name"
    name <- getLine
    base <- readFile "Films.txt"     -- base is the whole file contents as a single string
    print $moviesBy name $lines base

moviesBy :: String -> [String] -> [[String]]
moviesBy name (title:director:year:_:others) | director == name = [title, director, year]:moviesBy name others
                                             | otherwise = moviesBy name others -- a different director, scan the rest of the file
moviesBy _ _ = [] -- when there's no more records

更详细......

lines base将行中的文件内容拆分(删除换行符),生成字符串列表。

moviesBy接受一个字符串作为搜索模式,以及一个字符串列表,它是您文件的内容。从这个文件的创建方式来看,我们希望在每四个第二行中找到导演的名字。这是第一次模式匹配:

moviesBy name (title:director:year:_:others)

这里,(title:director:year:_:others)匹配至少四个元素的列表,将它们绑定到相关变量(第四个位置_是一个通配符模式,在这里与空白字符串匹配,这是无对我们很重要)。 others,作为:最右边的操作数,因此匹配列表的剩余部分(第4尾,用Lisp的说法)。在管道|之后,我们在匹配上添加了一个额外的约束,四元组中的第二个元素应该等于导演的关注名称。如果为true,则在输出中插入[title, director, year]的列表(作为生成规则的右侧部分:的RHS上的=的左操作数)和剩余的通过递归调用(该RHS other的右操作数)检查列表的一部分(:); otherwise跳过此四元组,只考虑其余部分。

最后一行中的匹配处理少于四个元素的任何列表(可能是文件的末尾)。由于我们不太可能在如此短的列表中找到更多导演的电影,我们只需返回[]

所以,例如,如果我们有一个列表

["Blade Runner", "Ridley Scott", "1982", " ", "Alien", "Ridley Scott", "1979", " "]
然后找我们获得的斯科特电影:

  1. 首先,列表与(title:director:year:_:others)匹配。然后绑定变量:title是&#34; Blade Runner&#34;,director是&#34; Riddley Scott&#34;,year是&#34; 1982&#34 ; others["Alien", "Ridley Scott", "1979", " "]。由于director等于我们正在寻找的名称,因此我们采用第一条路径并宣布["Blade Runner", "Ridley Scott", "1982"]:moviesBy "Ridley Scott" ["Alien", "Ridley Scott", "1979", " "]为我们的结果。

  2. 接下来,按照递归调用来构造结果列表的尾部。同样,title是&#34; Alien&#34;,director&#34; Ridley Scott&#34;,year是&#34; 1979&#34;并且others绑定到一个空列表。因此,步骤1中结果列表的尾部是["Alien", "Ridley Scott", "1979"]:moviesBy "Ridley Scott" []

  3. 最后一次递归调用。我们不能将至少四个元素模式绑定到空列表,所以我们采用匹配字符串和列表的任意组合的最后一个替代moviesBy _ _,这里的结果是[](递归停止)。因此,步骤2的结果是["Alien", "Ridley Scott", "1979"]:[],换句话说,[["Alien", "Ridley Scott", "1979"]]。并且在头部前面加上1.,函数的总结果为[["Blade Runner", "Ridley Scott", "1982"], ["Alien", "Ridley Scott", "1979"]]