アルファベットの繰り上がり

cf. どう書く?.org - アルファベットの繰り上がり

succ でいいじゃん,と思ったらダメだった。

 Prelude> succ 'A'
 'B'
 Prelude> succ 'Z'
 '['

Ruby の String#succ はうまくやってくれるのに。


なら,26進数だと考えて素直に繰り上がりを処理すればいいか……と思ったけどこれもダメ。'A' は 0 じゃない。要するに 0 が無いんだな。結局繰り上がりのところで汚いコードになってしまった。

 module Main ( main ) where
 
 import Data.Char ( ord, chr )
 import Data.List ( mapAccumR, intersperse )
 
 
 succS :: [Char] -> Int -> [Char]
 succS s n = map intToAlpha $ g $ mapAccumR f n $ map alphaToInt s
   where
     alphaToInt c = (ord c ) - 64
     intToAlpha i = chr (i + 64)
     f acc x = let (d,m) = (acc+x) `divMod` 26
               in if m == 0  then (d-1,26)  else (d,m)
     g (0,b) = b
     g (a,b) = a:b
 
 
 main :: IO ()
 main = putStr $ concat $ intersperse "," $ take 100 $ iterate (flip succS 1) "A"

実行:

 ^o^ >runhaskell succS.hs
 A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,AA,AB,AC,AD,AE,AF,AG,AH,AI,A
 J,AK,AL,AM,AN,AO,AP,AQ,AR,AS,AT,AU,AV,AW,AX,AY,AZ,BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,
 BK,BL,BM,BN,BO,BP,BQ,BR,BS,BT,BU,BV,BW,BX,BY,BZ,CA,CB,CC,CD,CE,CF,CG,CH,CI,CJ,CK
 ,CL,CM,CN,CO,CP,CQ,CR,CS,CT,CU,CV