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

前端 未结 12 1262
感情败类
感情败类 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 09:00

    Along the lines of what other people have suggested, you can avoid having to reverse your string by using:

    import Data.Char (isSpace)
    
    dropFromTailWhile _ [] = []
    dropFromTailWhile p item
      | p (last items) = dropFromTailWhile p $ init items
      | otherwise      = items
    
    trim :: String -> String
    trim = dropFromTailWhile isSpace . dropWhile isSpace
    
    0 讨论(0)
  • 2021-01-01 09:07

    For sure, Data.Text is better for performance. But, as was mentioned, it's just fun to do it with lists. Here is a version that rstrip's the string in single pass (without reverse and ++) and supports infinite lists:

    rstrip :: String -> String
    rstrip str = let (zs, f) = go str in if f then [] else zs
        where
            go [] = ([], True)
            go (y:ys) =
                if isSpace y then
                    let (zs, f) = go ys in (y:zs, f)
                else
                    (y:(rstrip ys), False)
    

    p.s. as for infinite lists, that will work:

    List.length $ List.take n $ rstrip $ cycle "abc  "
    

    and, for obvious reason, that will not (will run forever):

    List.length $ List.take n $ rstrip $ 'a':(cycle " ")
    
    0 讨论(0)
  • 2021-01-01 09:08

    This should be right about O(n), I believe:

    import Data.Char (isSpace)
    
    trim :: String -> String
    -- Trimming the front is easy. Use a helper for the end.
    trim = dropWhile isSpace . trim' []
      where
        trim' :: String -> String -> String
        -- When finding whitespace, put it in the space bin. When finding
        -- non-whitespace, include the binned whitespace and continue with an
        -- empty bin. When at the end, just throw away the bin.
        trim' _ [] = []
        trim' bin (a:as) | isSpace a = trim' (bin ++ [a]) as
                         | otherwise = bin ++ a : trim' [] as
    
    0 讨论(0)
  • 2021-01-01 09:09

    Nowadays the MissingH package ships with a strip function:

    import           Data.String.Utils
    
    myString = "    foo bar    "
    -- strip :: String -> String
    myTrimmedString = strip myString
    -- myTrimmedString == "foo bar"
    

    So if the conversion from String to Text and back does not make sense in your situation, you could use the function above.

    0 讨论(0)
  • 2021-01-01 09:11

    I don't know anything about the runtime or efficiency but what about this:

    -- entirely input is to be trimmed
    trim :: String -> String
    trim = Prelude.filter (not . isSpace')
    
    -- just the left and the right side of the input is to be trimmed
    lrtrim :: String -> String
    lrtrim = \xs -> rtrim $ ltrim xs
      where
        ltrim = dropWhile (isSpace')
        rtrim xs
          | Prelude.null xs = []
          | otherwise = if isSpace' $ last xs
                        then rtrim $ init xs
                        else xs 
    
    -- returns True if input equals ' '
    isSpace' :: Char -> Bool
    isSpace' = \c -> (c == ' ')
    

    A solution without using any other module or library than the Prelude.

    Some tests:

    >lrtrim ""
    >""
    
    >lrtrim "       "
    >""
    
    >lrtrim "haskell       "
    >"haskell"
    
    >lrtrim "      haskell       "
    >"haskell"
    
    >lrtrim "     h  a  s k e   ll       "
    >"h  a  s k e   ll"
    

    It could be runtime O(n).

    But I actually don't know it because I don't know the runtimes of the functions last and init. ;)

    0 讨论(0)
  • 2021-01-01 09:11

    Another (std) solution

    import System.Environment
    import Data.Text
    
    strip :: String -> IO String
    strip = return . unpack . Data.Text.strip . pack
    
    main = getLine >>= Main.strip >>= putStrLn
    
    0 讨论(0)
提交回复
热议问题