金額を漢字フォーマット

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/47175
ruby-listでこういうメールが飛んでいて、ちょっとやってみようかと思った。EmacsLispで。


まず
12345678912345
↑こんな数字があったとして、


(12345678912345)
リストにして


(1234567891 2345)
(123456 7891 2345) 
(12 3456 7891 2345)
こういうふうに、4桁ずつ分けて、あとから単位つければいいんじゃないかなと思った。


つまり、

carが10000より大きいか調べる
大きければ10000で割り、商と余りとcdrをくっつけた新しいリストを返す
小さければそのままのリストを返す

再帰的に行う。

(defun div-by-10000 (money-list)
  (let* ((money (car money-list))
	(larger-than-10000-p (> money 10000)))
    (cond (larger-than-10000-p
	   (div-by-10000 
	    (append (list (/ money 10000) (% money 10000)) (cdr money-list))))
	  (t money-list))))


で、次は得られた↓このリストをフォーマットする
(12 3456 7891 2345)


それには

("円" "万" "億" "兆" "京"
		  "垓" "抒" "穣" "溝" "澗"
		  "正" "載" "極" "恒河沙" 
		  "阿僧祇" "那由他" "不可思議" "無量大数")

こういうリストを用意して、mapする。

 (let* ((money-list (list money))
	 (units '("円" "万" "億" "兆" "京"
		  "垓" "抒" "穣" "溝" "澗"
		  "正" "載" "極" "恒河沙" 
		  "阿僧祇" "那由他" "不可思議" "無量大数")))
    (map 'list #'concat (reverse (map 'list #'number-to-string (div-by-10000 money-list))) units))


で、あとは
("2345円" "7891万" "3456億" "12兆")
これをひっくり返してつなげればよろし。
reduceを使うと便利。


全貌

(defun div-by-10000 (money-list)
  (let* ((money (car money-list))
	(larger-than-10000-p (> money 10000)))
    (cond (larger-than-10000-p
	   (div-by-10000 
	    (append (list (/ money 10000) (% money 10000)) (cdr money-list))))
	  (t money-list))))

(defun format-money (money)
  (let* ((money-list (list money))
	 (units '("円" "万" "億" "兆" "京"
		  "垓" "抒" "穣" "溝" "澗"
		  "正" "載" "極" "恒河沙" 
		  "阿僧祇" "那由他" "不可思議" "無量大数"))
	 (money-list (map 'list #'concat 
			  (reverse 
			   (map 'list #'number-to-string 
				(div-by-10000 money-list))) units)))
    (reduce #'concat (reverse money-list ))))

(format-money 12345678912345)
=> "12兆3456億7891万2345円"


ナユタ、フカシギくらいでっかい数やろうとするとoverflowエラーなってしまうw


2010/07/19 追記
Rubyでの例を見っけ

億とか京とか - しょんぼり技術メモ
http://d.hatena.ne.jp/syonbori_tech/20100623/1277299525