How to split a string in Haskell?

后端 未结 13 1571
日久生厌
日久生厌 2020-11-28 03:08

Is there a standard way to split a string in Haskell?

lines and words work great from splitting on a space or newline, but surely there is

相关标签:
13条回答
  • 2020-11-28 03:56

    There is a package for this called split.

    cabal install split
    

    Use it like this:

    ghci> import Data.List.Split
    ghci> splitOn "," "my,comma,separated,list"
    ["my","comma","separated","list"]
    

    It comes with a lot of other functions for splitting on matching delimiters or having several delimiters.

    0 讨论(0)
  • 2020-11-28 03:57

    In the module Text.Regex (part of the Haskell Platform), there is a function:

    splitRegex :: Regex -> String -> [String]
    

    which splits a string based on a regular expression. The API can be found at Hackage.

    0 讨论(0)
  • 2020-11-28 03:58

    I started learning Haskell yesterday, so correct me if I'm wrong but:

    split :: Eq a => a -> [a] -> [[a]]
    split x y = func x y [[]]
        where
            func x [] z = reverse $ map (reverse) z
            func x (y:ys) (z:zs) = if y==x then 
                func x ys ([]:(z:zs)) 
            else 
                func x ys ((y:z):zs)
    

    gives:

    *Main> split ' ' "this is a test"
    ["this","is","a","test"]
    

    or maybe you wanted

    *Main> splitWithStr  " and " "this and is and a and test"
    ["this","is","a","test"]
    

    which would be:

    splitWithStr :: Eq a => [a] -> [a] -> [[a]]
    splitWithStr x y = func x y [[]]
        where
            func x [] z = reverse $ map (reverse) z
            func x (y:ys) (z:zs) = if (take (length x) (y:ys)) == x then
                func x (drop (length x) (y:ys)) ([]:(z:zs))
            else
                func x ys ((y:z):zs)
    
    0 讨论(0)
  • 2020-11-28 03:59

    Remember that you can look up the definition of Prelude functions!

    http://www.haskell.org/onlinereport/standard-prelude.html

    Looking there, the definition of words is,

    words   :: String -> [String]
    words s =  case dropWhile Char.isSpace s of
                          "" -> []
                          s' -> w : words s''
                                where (w, s'') = break Char.isSpace s'
    

    So, change it for a function that takes a predicate:

    wordsWhen     :: (Char -> Bool) -> String -> [String]
    wordsWhen p s =  case dropWhile p s of
                          "" -> []
                          s' -> w : wordsWhen p s''
                                where (w, s'') = break p s'
    

    Then call it with whatever predicate you want!

    main = print $ wordsWhen (==',') "break,this,string,at,commas"
    
    0 讨论(0)
  • 2020-11-28 03:59

    I find this simpler to understand:

    split :: Char -> String -> [String]
    split c xs = case break (==c) xs of 
      (ls, "") -> [ls]
      (ls, x:rs) -> ls : split c rs
    
    0 讨论(0)
  • 2020-11-28 04:05

    In addition to the efficient and pre-built functions given in answers I'll add my own which are simply part of my repertory of Haskell functions I was writing to learn the language on my own time:

    -- Correct but inefficient implementation
    wordsBy :: String -> Char -> [String]
    wordsBy s c = reverse (go s []) where
        go s' ws = case (dropWhile (\c' -> c' == c) s') of
            "" -> ws
            rem -> go ((dropWhile (\c' -> c' /= c) rem)) ((takeWhile (\c' -> c' /= c) rem) : ws)
    
    -- Breaks up by predicate function to allow for more complex conditions (\c -> c == ',' || c == ';')
    wordsByF :: String -> (Char -> Bool) -> [String]
    wordsByF s f = reverse (go s []) where
        go s' ws = case ((dropWhile (\c' -> f c')) s') of
            "" -> ws
            rem -> go ((dropWhile (\c' -> (f c') == False)) rem) (((takeWhile (\c' -> (f c') == False)) rem) : ws)
    

    The solutions are at least tail-recursive so they won't incur a stack overflow.

    0 讨论(0)
提交回复
热议问题