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

お題だけ拝借。

 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"