In Haskell, how do you trim whitespace from the beginning and end of a string?

前端 未结 12 1261
感情败类
感情败类 2021-01-01 08:45

How do you trim whitespace from the start and end of a string?

trim \"  abc \" 

=>

\"abc\"

Edit:

Ok, let me be a little cleare

相关标签:
12条回答
  • 2021-01-01 08:47

    After this question was asked (circa 2012) Data.List got dropWhileEnd making this a lot easier:

    trim = dropWhileEnd isSpace . dropWhile isSpace
    
    0 讨论(0)
  • 2021-01-01 08:51

    From: http://en.wikipedia.org/wiki/Trim_(programming)#Haskell

    import Data.Char (isSpace)
    
    trim :: String -> String
    trim = f . f
       where f = reverse . dropWhile isSpace
    
    0 讨论(0)
  • 2021-01-01 08:51

    Inefficient but easy to understand and paste in where needed:

    strip = lstrip . rstrip
    lstrip = dropWhile (`elem` " \t")
    rstrip = reverse . lstrip . reverse
    
    0 讨论(0)
  • 2021-01-01 08:57

    I know this is an old post, but I saw no solutions that implemented good old fold.

    First strip the leading white-space using dropWhile. Then, using foldl' and a simple closure, you can analyze the rest of the string in one pass, and based on that analysis, pass that informative parameter to take, without needing reverse:

    import Data.Char (isSpace)
    import Data.List (foldl')
    
    trim :: String -> String
    trim s = let
      s'    = dropWhile isSpace s
      trim' = foldl'
                (\(c,w) x -> if isSpace x then (c,w+1)
                             else (c+w+1,0)) (0,0) s'
      in
       take (fst trim') s'
    

    Variable c keeps track of combined white and non white-space that should be absorbed, and variable w keeps track of right side white-space to be stripped.

    Test Runs:

    print $ trim "      a   b c    "
    print $ trim "      ab c    "
    print $ trim "    abc    "
    print $ trim "abc"
    print $ trim "a bc    "
    

    Output:

    "a   b c"
    "ab c"
    "abc"
    "abc"
    "a bc"
    
    0 讨论(0)
  • 2021-01-01 08:58

    If you have serious text processing needs then use the text package from hackage:

    > :set -XOverloadedStrings
    > import Data.Text
    > strip "  abc   "
    "abc"
    

    If you're too stubborn to use text and don't like the inefficiency of the reverse method then perhaps (and I mean MAYBE) something like the below will be more efficient:

    import Data.Char
    
    trim xs = dropSpaceTail "" $ dropWhile isSpace xs
    
    dropSpaceTail maybeStuff "" = ""
    dropSpaceTail maybeStuff (x:xs)
            | isSpace x = dropSpaceTail (x:maybeStuff) xs
            | null maybeStuff = x : dropSpaceTail "" xs
            | otherwise       = reverse maybeStuff ++ x : dropSpaceTail "" xs
    
    
    > trim "  hello this \t should trim ok.. .I  think  ..  \t "
    "hello this \t should trim ok.. .I  think  .."
    

    I wrote this on the assumption that the length of spaces would be minimal, so your O(n) of ++ and reverse is of little concern. But once again I feel the need to say that if you actually are concerned about the performance then you shouldn't be using String at all - move to Text.

    EDIT making my point, a quick Criterion benchmark tells me that (for a particularly long string of words with spaces and ~200 pre and post spaces) my trim takes 1.6 ms, the trim using reverse takes 3.5ms, and Data.Text.strip takes 0.0016 ms...

    0 讨论(0)
  • 2021-01-01 08:59

    You can combine Data.Text's strip with it's un/packing functions to avoid having overloaded strings:

    import qualified Data.Text as T
    
    strip  = T.unpack . T.strip . T.pack
    lstrip = T.unpack . T.stripStart . T.pack
    rstrip = T.unpack . T.stripEnd . T.pack
    

    Testing it:

    > let s = "  hello  "
    > strip s
    "hello"
    > lstrip s
    "hello  "
    > rstrip s
    "  hello"
    
    0 讨论(0)
提交回复
热议问题