在haskell中创建一个takeUntil函数

时间:2014-10-23 13:41:57

标签: haskell take

我想创建一个函数,当给出一个字符串,例如“ab”和“cdabd”时,它将用于这两个字符串,它将输出“cd”

到目前为止我还有这个

takeUntil :: String -> String -> String
takeUntil [] [] = []
takeUntil xs [] = []
takeUntil [] ys = []
takeUntil xs ys = if contains xs ys then -- ???? I get stuck here. 

contains函数是我之前定义的函数(整个函数应该不区分大小写) 包含功能:

contains :: String -> String -> Bool
contains _ [] = True
contains [] _ = False
contains xs ys = isPrefixOf (map toLower ys) (map toLower xs) || contains (tail(map toLower xs)      (map toLower ys)

2 个答案:

答案 0 :(得分:3)

有很多方法可以做到这一点,但继续你的路径,尝试以下方法:

import Data.List

takeUntil :: String -> String -> String
takeUntil [] [] = []                           --don't need this
takeUntil xs [] = [] 
takeUntil [] ys = [] 
takeUntil xs (y:ys) = if   isPrefixOf xs (y:ys)
                      then []
                      else y:(takeUntil xs (tail (y:ys)))

一些输出:

takeUntil "ab" "cdabd"
"cd"

takeUntil "b" "cdabd"
"cda"

takeUntil "d" "cdabd"
"c"

takeUntil "c" "cdabd"
""

takeUntil "xxx" "cdabd"
"cdabd"

修改

OP希望函数不区分大小写。

那么,你可以在很多方面做到这一点。例如,您可以编写一个lowerCase函数(我认为您已经在Data.Text中拥有它):

import qualified Data.Char as Char

lowerCase :: String -> String
lowerCase [] = []
lowerCase (x:xs) = (Char.toLower x):(lowerCase xs)

然后使用它(可能是丑陋而不是很实用):

takeUntil (lowerCase "cd") (lowerCase "abcDe")
"ab"

这是你期望的结果。

此外,您可以在lowerCase内使用takeUntil函数:

-- ...
takeUntil xs (y:ys) = if  isPrefixOf (lowerCase xs) (lowerCase (y:ys))
-- ...

所以,你可以这样做:

takeUntil "cd" "abcDe"
"ab"

无论如何,我认为最好的选择是@bheklilr建议。制作自己的isPrefixOfCaseless功能。

我希望这会有所帮助。

答案 1 :(得分:0)

在众多定义takeUntil的方法中,请考虑使用Data.Text函数,如下所示,

takeUntil :: String -> String -> String
takeUntil sep txt =  unpack $ fst $ breakOn (pack sep) (toCaseFold $ pack txt)

请注意,pack会将String转换为Text,而uncpak会反转toCaseFoldbreakOn用于不区分大小写的操作; String提供了一对,其中第一个元素包含文本,直到第一个(可能的)匹配。

<强>更新

此方法涵盖了已建议的测试,但此处并未预先设置原始takeUntil "e" "abcDe" "abcd"

{{1}}

解决这个问题涉及到例如在断点处通过索引进行拆分。