Skip to content

Instantly share code, notes, and snippets.

@ruthenium
Created September 14, 2012 16:00
Show Gist options
  • Save ruthenium/3722863 to your computer and use it in GitHub Desktop.
Save ruthenium/3722863 to your computer and use it in GitHub Desktop.
Split string by predicate including the matched element.
-----------------------------------------------------------------------------
{-| Split a 'String', by specified predicate, but do not remove matched
characters from the result.
Not an efficient implementation.
First, it folds a 'String' to a list of Strings.
Elements in the resulting list are in the reversed order, because they
are prepended to the final list, not appended.
At the end, it reverses the result.
-}
splitROne :: (Char -> Bool) -> String -> [String]
splitROne p = reverse . foldl (part) []
where
-- partition function
part :: [String] -> Char -> [String]
part [] c = [ [c] ] -- first letter
part lst@(x:xs) c | p c = [c]:lst -- predicate matches on letter, create new group
| otherwise = (x ++ [c]) : xs -- ordinary letter, add it to first group
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
{-| Split a 'String' by specified predicate, but do not remove matched
characters from the result.
Efficient recursive implementation inspired by the "Real World Haskell"
book.
NOTE:
This implementation may cause an empty first element of a result,
because the behaviour of the 'break' function.
-}
splitRTwo :: (Char -> Bool) -> String -> [String]
splitRTwo p s =
let (b, r) = break p s
in b : case r of
[] -> []
(h:t) -> (h : hs) : ts
where
(hs:ts) = splitRTwo p t
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
{-| Split a 'String' by specified predicate, but do not remove matched
characters from the result.
Efficient recursive implementation inspired by the "Real World Haskell"
book. The same as above, but implemented another way,
using case and where.
NOTE:
This implementation may cause an empty first element of a result,
because the behaviour of the 'break' function.
-}
splitRThree :: (Char -> Bool) -> String -> [String]
splitRThree p s = case break p s of
(b, []) -> [ b ]
(b, (h:t)) -> b : (h : hs) : ts
where
(hs:ts) = splitRThree p t
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
{-| Split a 'String' by specified predicate, but do not remove matched
characters from the result.
Recursive implementation inspired by the "Real World Haskell" book.
This implementation variant holds the first and the rest matches
separately.
The inner local function 'go' accepts a previously matched character
and joins it with the result, so extra splitting it is not needed.
The algorithm is similar to the functions above.
-}
splitRFour :: (Char -> Bool) -> String -> [String]
splitRFour _ [] = []
splitRFour p s = case break p s of
(b, []) -> [ b ] -- no characters matching predicate in the string
([], (h:t)) -> go h t -- first character of the string matches predicate
(b, (h:t)) -> b : go h t
where
go :: Char -> String -> [String]
go m s' = case break p s' of
(b', []) -> [ m:b' ]
(b', (x:xs)) -> (m : b') : go x xs
-----------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment