获取字符串列表并用一个替换多个单词

时间:2014-01-29 03:01:49

标签: string list haskell recursion

我对Haskell相当新,作为输入,我想以一个字符串数组为例 ["HEY" "I'LL" "BE" "RIGHT" "BACK"]并查找允许说"BE" "RIGHT" "BACK"并将其替换为其他字词,让我们说"CHEESE"。我有一个单个单词的功能,但如果一个字符串包含某个短语用一个单词替换它,我想要这个。哦,我不想使用外部库。

代码:

replace :: [String] -> [String]
replace [] = []
replace (h:t)
    | h == "WORD" = "REPLACED" : replace t
    | otherwise = h : replace t

1 个答案:

答案 0 :(得分:1)

您现在拥有的内容也可以实现为

replace ("WORD":rest) = "REPLACED" : replace rest
replace (x:rest) = x : replace rest
replace [] = []

这可以扩展到你的例子

replace ("BE":"RIGHT":"BACK":rest) = "CHEESE" : replace rest
replace (x:rest) = x : replace rest
replace [] = []

但显然这不是写它的好方法。我们想要一个更通用的解决方案,我们可以传入一个短语(或子列表)来替换。首先,我们了解以下事项:

  1. 输入是n元素的列表(在我们递归时减少)
  2. 短语是m元素的列表(在我们递归时保持不变)
  3. 如果m > n,我们肯定没有匹配
  4. 如果m <= n,我们可能会匹配
  5. 如果我们没有匹配,请保持头部并尝试尾巴
  6. 虽然有更高效的算法,但一个简单的算法就是检查列表中每一步的长度。这可以简单地完成

    --             Phrase    Replacement  Sentence   New sentence
    replaceMany :: [String] -> String -> [String] -> [String]
    replaceMany phrase new sentence = go sentence
        where
            phraseLen = length phrase
            go []   = []
            go sent@(x:xs)
                | sentLen < phraseLen = sent
                | first == phrase     = new : go rest
                | otherwise           = x : go xs
                where
                    sentLen = length sent
                    first   = take phraseLen sent
                    rest    = drop phraseLen sent
    

    在这里,我们可以利用Haskell的懒惰,然后继续定义firstrest,而不必担心它是否有效。如果不使用它们,它们永远不会被计算出来。我选择在sent@(x:xs)格式中使用一些更复杂的模式匹配。这会匹配包含至少一个元素的列表,将整个列表分配到sent,将第一个元素分配给x,将列表的尾部分配给xs。接下来,我们只检查每个条件。如果sentLen < phraseLen,那么列表的其余部分就不可能存在匹配,所以只返回整个事情。如果第一个m元素等于我们的短语,则替换它并继续搜索,否则只需放回第一个元素并继续搜索。