将字符串拆分为Clean中的字符串列表

时间:2014-10-14 09:24:54

标签: string split functional-programming clean-language

由于资源有限,我需要提出一个问题 here 。我一直在努力学习函数式编程,无尽的Haskell教程并不能帮助我。因此,我想用Clean语言实现的是将" car cow cat "之类的字符串拆分为字符串列表["car","cow","cat"]。你能给我一个详细的答案(不一定是完整的代码),关于如何遍历这个字符串,特别是当新构造的字符串被添加到列表时的部分?

2 个答案:

答案 0 :(得分:3)

我将提供一个简单的解决方案。在Haskell中有更好的方法可以做到这一点,但对于函数式编程的新人来说,它是最简单的,没有使用任何特定的Haskell函数,比如takeWhile,甚至任何折叠和映射...

你基本上想要模拟迭代列表,所以我建议这样做:

  1. 定义一个将采用字符串和拆分字符的函数。此函数将返回字符串列表 - spliton :: String -> Char -> [String]

  2. 要移动列表,我们会想要吞噬字符,直到我们点击其中一个分裂字符为止。我们还想保存到目前为止保存的单词以及整个单词列表。 为此,我们将定义一个将保存状态的子功能

    spliton' :: String -> Char -> String -> [String] -> [String]

    spliton' [] _ sofar res = res ++ [sofar]

    我还包括最简单的子句 - 空字符串。当我们的字符串为空时,我们只想返回到目前为止保存的内容。

  3. 现在让我们继续我们的实际递归函数: 如果我们点击了分割字符,我们将到目前为止保存的字符串添加到列表中并使用空的当前状态字符串重新启动 如果我们没有点击分裂字符,我们会将字符添加到当前状态字符串

    spliton' (currchar:rest) splitby sofar res
         | currchar==splitby = spliton' rest splitby "" (res++[sofar])
         | otherwise = spliton' rest splitby (sofar++[currchar]) res
    
  4. 所以,总结一下我们的代码:

    spliton :: String -> Char -> [String]
    spliton source splitchar = spliton' source splitchar [] []
    
    spliton' :: String -> Char -> String -> [String] -> [String]
    spliton' [] _ sofar res = res ++ [sofar]
    spliton' (currchar:rest) splitby sofar res
             | currchar==splitby = spliton' rest splitby "" (res++[sofar])
             | otherwise = spliton' rest splitby (sofar++[currchar]) res
    

    注意:然而,这不会消除空字符串 - 这意味着如果你有许多多余的空格 - 你将把它们添加到列表中。我会让你思考如何处理这个案子 - 希望这可以帮助你开始。

答案 1 :(得分:2)

让我们将其分解为几个子问题:

  1. 从字符串中创建一个字符列表,以便我们可以轻松应用模式匹配。
  2. 抓取列表的初始部分(尽可能只使用空格或仅使用非空格),并且只在不是空格时保留它。
  3. 在列表非空时重复第二步。
  4. 首先可以使用fromString完成。对于第二步和第三步,我们定义了一个辅助函数:

    scrape :: [Char] -> [String]
    scrape [] = []
    scrape cs=:[c:_]
    | isSpace c = scrape (dropWhile isSpace cs)
    | otherwise = [toString word:scrape rest]
    where
        (word,rest) = span (not o isSpace) cs
    

    第一种选择是匹配空列表的基本案例。第二个备选方案将整个列表cs与第一个元素c匹配。如果第一个字符是空格,我们递归(步骤3)在同一列表上调用相同的函数而不使用空格的初始部分。如果第一个字符不是空格,我们使用span :: (a -> Bool) [a] -> ([a], [a])分割作为单词的初始部分中的列表,其余部分。我们使用toString作为字符串存储单词,并以递归方式为列表的其余部分调用scrape

    现在,我们只需要一个包装器来使其成为类型String -> [String]

    的函数
    split :: String -> [String]
    split s = scrape (fromString s)
    where
        scrape :: [Char] -> [String]
        scrape [] = []
        scrape cs=:[c:_]
        | isSpace c = scrape (dropWhile isSpace cs)
        | otherwise = [toString word:scrape rest]
        where
            (word,rest) = span (not o isSpace) cs
    

    请注意,您可以通过传递字符d并将isSpace c替换为c == d并将(not o isSpace)替换为((<>) d),轻松地从分隔符进行抽象。或者,您可以选择不传递字符d,而是传递函数isDelim :: Char -> Bool。然后,您分别获得isDelim c(not o isDelim)