tags:

views:

189

answers:

5

What is the (or is there an) idiomatic way to strip newlines from strings in Haskell? Or do I have to craft my own by finding the trailing newlines/spaces and then removing them?

EDIT: I'm looking for what Python's rstrip does, but don't need the optional "chars" argument:

string.rstrip(s[, chars])

Return a copy of the string with trailing characters removed. If chars is omitted or None, whitespace characters are removed. If given and not None, chars must be a string; the characters in the string will be stripped from the end of the string this method is called on.

+2  A: 

Depending on what you mean:

Prelude> filter (/= '\n') "foo\n\nbar\n"
"foobar"

Prelude> words "foo\n\nbar\n"
["foo","bar"]

But these don't deal with spaces nicely. So perhaps not what you're looking for.

dino
Neither of these actually "strips" the string, though (in the usual sense of "remove leading or trailing characters").
Travis Brown
+9  A: 

Here's one simple implementation (adapted from Wikipedia):

import Data.Char (isSpace)
rstrip = reverse . dropWhile isSpace . reverse

There's also an rstrip already defined in Data.String.Utils.

(By the way, Hayoo! is a great resource for this kind of question: a search for rstrip takes you directly to Data.String.Utils.)

Travis Brown
I never looked in Data.String.Utils before. Useful. And rstrip looks like exactly what is wanted.
Tim Perry
+1  A: 

There is a sample in Chapter 4 of real world haskell which does the splitting you want. You'll need to paste the pieces back together when you are done. http://book.realworldhaskell.org/read/functional-programming.html

Search for "Warming up: portably splitting lines of text" in the text.

Tim Perry
+1  A: 

I used this the other day:

Prelude> let trimnl = reverse . dropWhile (=='\n') . reverse
Prelude> trimnl ""
""
Prelude> trimnl "\n"
""
Prelude> trimnl "a\n"
"a"
Prelude> trimnl "a\n\n"
"a"
Prelude> trimnl "a\nb\n"
"a\nb"
Simon Michael
That's the same principle as Travis's answer.
KennyTM
Yes, I guess we typed at the same time. But mine does what the poster asked for! Vote for me! :)
Simon Michael
I think trimnl = reverse. dropwhile (`elem` "\n\r\t ") . reverse would be closer to the rtrim in python
Tim Perry
In case anyone cares, my call to elem lost the back-ticks around it when I submitted the comment.
Tim Perry
Tim: I'm not sure what SO escape is (\`testing\` - yep it's \\), but for Haskell you can at least use flip. `trimnl = reverse . dropWhile (flip elem "\n\r\t")`.
TomMD
+1  A: 

If this is for a typical file-reading application, then you should probably start with lines. This may allow you to avoid Data.String.Utils.rstrip completely:

> lines "one time\na moose\nbit my sister\n"
["one time", "a moose", "bit my sister"]

As you can see, lines takes the text of the entire file and properly turns each line into a string with no trailing newline. This means you can write a program like so:

main = mapM_ (putStrLn . process) . lines =<< readFile "foo.txt"
  where process :: String -> String
        process = -- your code here --
Nathan Sanders