文字列のセンタリング
Posted feedbacks - Haskell
1 2 3 4 5 6 7 8 9 | center :: Int -> [Char] -> [Char]
center n str | slen < n = center'
| slen > n = clop
| otherwise = str
where
slen = length str
center' = lmargin ++ str ++ rmargin
(lmargin, rmargin) = splitAt ((n-slen) `div` 2) $ replicate (n-slen) ' '
clop = take n $ drop ((slen-n) `div` 2) str
|
Haskellらしく無限リストと高階関数で。 1. 文字列の右に無限個の空白を連結 2. 左側を揃える 3. 幅の分だけ切り取る
1 2 3 4 5 | center width str = take width . adjust lmargin $ str ++ repeat ' '
where
lmargin = (width - length str) `div` 2
adjust n | n > 0 = (replicate n ' ' ++)
| otherwise = drop (-n)
|
覚えたてのControl.Monad.Fixを使って。
1 2 3 4 5 6 7 8 9 10 | import Control.Monad.Fix
center :: Int -> String -> String
center n = fix (\f x -> g f x)
where g f x | length x1 == n = x1
| length x2 == n = x2
| length x2 > n = f x2
| otherwise = f $ head $ zipWith3 (\x y z -> x ++ y ++ z) [" "] [x] [" "]
where x1 = tail x
x2 = init x1
|
明示的算術演算なし、lengthで文字列の長さも測っていない、「そこまでしたからってどうよ」版 ^^; あ。それから、このセンタリングでは空白は前より入り、切り落としは後ろよりになります。 center 2 "a" → "_a" center 3 "a" → "_a_" center 3 "ab" → "_ab" center 4 "ab" → "_ab_" center 3 "abcde" → "bcd" center 4 "abcde" → "bcde" center 3 "abcdef" → "bcd" center 4 "abcdef" → "bcde"
1 2 3 4 5 6 7 8 9 10 11 | center n s = uncurry (c n []) $ halve s
where c 0 a p q = take n (a ++ q)
c i a p q = d (pred i) (head p:a) (tail p) q
d 0 a p q = take n (a ++ q)
d i a p q = c (pred i) a p q
halve s = e (repeat ' ') (s++repeat ' ') s
where e a b [] = (a,b)
e a b c = o (head b:a) (tail b) (tail c)
o a b [] = (a,b)
o a b c = e a b (tail c)
|
なかなか面白い問題でした。
最初は文字列が指定より長い場合、短かい場合の処理を別々に書いてたのですが、 (空白を)「くわえる」と「削る」以外の部分は共通にできる事に気がつきました。
1 2 3 4 5 6 7 | center n str = let s = (n - length str)
s1 = div s 2
s2 = s - s1
in reverse.format s2.reverse.format s1 $ str
where format n
| n >= 0 =(replicate n ' '++)
|otherwise = drop (-n)
|



nobsun
#4089()
Rating1/3=0.33
文字列を指定のカラム幅にセンタリング配置する関数を示してください。文字列の長さが指定した幅より長い場合には文字列の両端をできるだけ均等に切り落して指定幅に収めてください。1文字は1カラムに収まるものと仮定してかまいません。
[ reply ]