Programming Praxis – Entab And Detab

In today’s Programming Praxis exercise, our goal is to write two functions to convert between text fragments indented with tabs and spaces. Let’s get started, shall we?

A required import:

import Text.Regex

Converting tabs to spaces is easy: just replace each tab with the desired amount of spaces. For the actual replacing we use a regular expression library.

detab :: Int -> String -> String
detab w s = subRegex (mkRegex "\t") s (replicate w ' ')

Converting spaces to tabs is a bit more complicated, particularly if the text is indented using a combination of tabs and spaces. First we count the total indent length, and then we insert the required amount of tabs and spaces.

entab :: Int -> String -> String
entab w = unlines . map f . lines where
    f s = replicate tabs '\t' ++ replicate spaces ' ' ++ line where
        (indent, line) = span (`elem` " \t") s
        (tabs, spaces) = divMod (sum $ map width indent) w
    width c = if c == '\t' then w else 1

For testing, we need to make sure we handle all the test cases: no indent, less than a tab of indent, one tab of indent, less than two tabs of indent, two tabs of indent and a line with mixed spaces and tabs.

main :: IO ()
main = do print $ entab 2 "a\n b\n  c\n   d\n    e\n \t f\n" ==
                          "a\n b\n\tc\n\t d\n\t\te\n\t\tf\n"
          print $ detab 2 "a\n b\n\tc\n\t d\n\t\te\n \t f\n" ==
                          "a\n b\n  c\n   d\n    e\n    f\n"

Everything seems to be working correctly. Personally, I’m on the spaces side of this particular holy war, specifically in the four spaces camp. Two spaces is still acceptable, every other setting is wrong 🙂

Tags: , , , , , , , , , ,

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: