在haskell中生成takeUntil函数

在haskell中生成takeUntil函数,haskell,take,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

我想做一个函数,当给定一个字符串如“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)

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

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希望函数不区分大小写

好吧,同样,你可以通过很多方式做到这一点。例如,您可以编写一个
小写
函数,如(我想您在
Data.Text
中已经有了它):

然后像这样使用它(可能很丑而且不太实用):

这就是你所期望的结果

此外,您还可以使用
takeUntil
中的
小写
函数:

-- ...
takeUntil xs (y:ys) = if  isPrefixOf (lowerCase xs) (lowerCase (y:ys))
-- ...
所以,你可以这样做:

takeUntil "cd" "abcDe"
"ab"
无论如何,我认为最好的选择是@bheklillr建议的。让您自己的
isPrefixOfCaseless
功能


我希望这有帮助。

< P>在定义<代码>直到的多种方法中,考虑使用以下函数,

takeUntil :: String -> String -> String
takeUntil sep txt =  unpack $ fst $ breakOn (pack sep) (toCaseFold $ pack txt)
请注意,
pack
字符串
转换为
文本
,而
unpak
则相反
toCaseFold
用于不区分大小写的操作
breakn
提供一对,其中第一个元素包含文本,直到第一个(可能)匹配为止

更新

这种方法涵盖了已经建议的测试,但它没有保存原始的
字符串
,例如

takeUntil "e" "abcDe"
"abcd"

解决这一问题的方法包括,例如,在断点处按索引进行拆分。

您的定义有点错误,您的意思是最后4行的
takeUntil
?是的。如果你能发布
包含的代码,或者至少是类型签名和它的功能的更具体的描述,那将非常有帮助。我猜我可能需要一个帮助函数来定义如果xs在ys中会发生什么。helper函数应该在匹配两个字符串之前切断所有内容,即“ab”“cdab”=“cd”解决此问题的方法很多,但我认为使用
contains
会让事情变得困难。首先,如果我传入
takeUntil“ab”“abcdab”
,该怎么办?使用
contains
,将返回
,而不是
“cdab”
。直接使用
isPrefixOf
将是一个更好的选择,就像@JosEdu所做的那样。谢谢,但问题是我需要使它不区分大小写,这样如果“cd”“abcDe”,它仍然会给我“ab”尝试在
xs
y
上使用
toLower
from
Data.Char
take的第一个案例被第二个案例包含,因此可以删除它。另外,
tail(y:ys)
可以简化为
ys
@Nicholas如果您想执行此检查而不区分大小写,我建议创建一个
isPrefixOfCaseless
(比
isPrefixOfCaseInsensitive
短的名称)函数,在其参数上本地映射
到lower
。您最终会复制一些操作,但在这种情况下,最好让它工作,而不是让它尽快运行。对,
caselessPrefixOf pre-list=isPrefixOf(map-toLower-pre)(map-toLower-list)
很有价值。您也可以使用数据列表中的其他函数
takeUntil xs ys=maybe ys fst$find(isPrefixOf xs.snd)$zip(inits ys)(tails ys)
将其简化为一个具有复杂逻辑的单行程序,您可以在
caselessPrefixOf
中进行交换。
takeUntil :: String -> String -> String
takeUntil sep txt =  unpack $ fst $ breakOn (pack sep) (toCaseFold $ pack txt)
takeUntil "e" "abcDe"
"abcd"