How do you trim whitespace from the start and end of a string?
trim \" abc \"
=>
\"abc\"
Edit:
Ok, let me be a little cleare
After this question was asked (circa 2012) Data.List
got dropWhileEnd
making this a lot easier:
trim = dropWhileEnd isSpace . dropWhile isSpace
From: http://en.wikipedia.org/wiki/Trim_(programming)#Haskell
import Data.Char (isSpace)
trim :: String -> String
trim = f . f
where f = reverse . dropWhile isSpace
Inefficient but easy to understand and paste in where needed:
strip = lstrip . rstrip
lstrip = dropWhile (`elem` " \t")
rstrip = reverse . lstrip . reverse
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"
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...
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"