2014-10-23 1 views
2

Я хочу сделать функцию, которая, когда дана строка, например, «AB» и «cdabd», когда он будет использоваться на этих двух строк он будет выводить «CD»делает функцию takeUntil в Haskell

у меня есть это вверх в настоящий

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

класса содержит функцию, в которой я определил ранее (вся эта функция должна быть чувствительна к регистру) содержит функции:

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) 
+1

Ваше определение немного неверно, вы имели в виду 'takeUntil' на последних 4 строках? – bheklilr

+0

да я. это должно быть takeUntil – Nicholas

+0

Кроме того, было бы очень полезно, если бы вы могли опубликовать код для 'contains', или, по крайней мере, подпись типа и более конкретное описание того, что он делает. – bheklilr

ответ

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" 

EDIT:

ОП хочет функция быть прецедентного нечувствительны.

Ну, снова вы можете сделать это множеством способов. Например, вы можете написать 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.

Надеюсь, это поможет.

+0

Спасибо, но я должен сделать его регистрозависимым, чтобы, если «cd» «abcDe», он будет давать мне «ab» – Nicholas

+0

попробуйте использовать 'toLower' из' Data.Char' как на 'xs', так и' y' – Arnon

+0

Первый случай 'takeUntil' подставляется вторым, поэтому его можно удалить. Кроме того, 'tail (y: ys)' можно упростить до 'ys'. – chi

0

В многочисленных подходов для определения takeUntil, рассмотреть возможность использования Data.Text функции следующим образом,

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

Обратите внимание, что pack преобразует String в Text, в то время как uncpak делает обратное; toCaseFold для операций без учета регистра; breakOn поставляет пару, где первый элемент содержит текст до первого (возможного) совпадения.

Update

Этот подход охватывает тесты уже предложенные, но не preseve оригинальный String например здесь,

takeUntil "e" "abcDe" 
"abcd" 

работа вокруг этого включает в себя, например, расщепление по индексу на разрыв точка.

Смежные вопросы