お題だけ拝借。
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"
mapAccumL を使ってみました。
import List
untabify n xs = concat $ snd $ mapAccumL f 0 xs where
f s ’¥t’ = (0, replicate (s `mod` n) ’ ’)
f s c = (s-1, [c])