タブをスペースで展開する

お題だけ拝借。

cf. Gaucheクックブック - タブをスペースで展開する

1文字ずつ処理する。正規表現を使ったり日本語を考慮するのはパス。

 untabify :: Int -> String -> String
 untabify w = f "" 0
   where
     f r _ []                 = r
     f r p (c:cs) | '\t' == c = f (r ++ replicate (ts p) ' ') (p + ts p) cs
                  | otherwise = f (r ++ [c]) (p + 1) cs
     ts p = w - p `mod` w

はじめは foldl を使おうと思ったけど f の引数が3つになる(展開後の文字列を位置を蓄積する必要がある)のであきらめた。あと,haskell らしくリストの引数は後ろに。
実行例。

 *Main> untabify 8 "012\t012345\t01"
 "012     012345  01"

タブ幅は2文字がすき。

 *Main> untabify 2 "012\t012345\t01"
 "012 012345  01"


あ,そうか。f の引数をタプル(ペア)にしてやれば foldl が使えるんだ。

 untabify2 :: Int -> String -> String
 untabify2 w = fst . foldl f ("", 0)
   where
     f (r, p) c | '\t' == c = ( r ++ replicate (ts p) ' ' , p + ts p )
                | otherwise = ( r ++ [c]                  , p + 1    )
     ts p = w - p `mod` w
 *Main> untabify2 8 "012\t012345\t01"
 "012     012345  01"
 *Main> untabify2 2 "012\t012345\t01"
 "012 012345  01"