2016-09-05 2 views
2

cl-formatを使ってお金をフォーマットしようとしています。私は(f 12345.555) ;=> "12,345.56"がほしいです。私はフォーマット文字列"~$"で小数点を得て、"~:D"でコンマ区切りを取得します。どのようにそれらを組み合わせるのですか?cl-format(一般的なlispフォーマット関数の実装)のお金をフォーマットする方法

+0

これはおそらく重複していませんが、[一般的なlispではどのように浮動小数点をフォーマットし、グループ化、グループのcharとdecimal separator charを指定することができますか(http://stackoverflow.com/q/35012859/1281433)おそらくここでは関連性があります。 –

答えて

0

問題の一部は、全体の数が渡された場合~:dディレクティブは唯一の小数点以下のゼロ以外の何かがあるのIE場合、(それは浮動小数点数または整数のかどうか)カンマを追加することで、~:d同じように番号を出力しますです。これは、CLのformatとClojureのcl-formatの場合に当てはまります。

解決方法は、数値を整数と小数に分割し、それらを別々にフォーマットすることです。これを行う1つの方法は、truncate関数を使用します。これは、Clojureも標準ライブラリも提供していません。ここでは、floorceilclojure.math.numeric-towerから使用する方法があります。 (以前のバージョンのバグを指摘してくれたコアダンプのおかげで)

(defn truncate [x] 
    (if (neg? x) 
    (ceil x) 
    (floor x))) 

(defn make-money [x] 
    (let [int-part (truncate x) 
     dec-part (- x int-part)] 
    (cl-format nil "~:d~$" int-part dec-part))) 

(make-money 123456789.123456789) ;=> "123,456,7890.12" 

これは、正の数でのみ動作するように設計されていることに注意してください。 (編集:Xaviがコメントで指摘したように、最後のコメントの後に4桁のグループがあるので、解決策ではありません)

OPの質問に答えますしかし、Common Lispでは~$の動作が少し違っています。デフォルトでは小数点の前の最初のゼロを出力します(少なくとも私が試した実装では - これが標準化されているかどうかはわかりません)。

(defun make-money (x) 
    (let* ((int-part (truncate x)) 
     (dec-part (- x int-part))) 
    (format nil "~:d~0,2f" int-part dec-part))) 

数字が大きすぎる場合は、この定義で予期しない結果を得ることができます(詳細については、Peter Seibel's introductionを参照)あまりにも、Clojureの中でこのように動作します - これは~fディレクティブをカスタマイズすることで回避することができます。 Joshua Taylorのコメントによると、Common Lispでこれを行うための他の、おそらくより良い方法があると思いますが、この問題を避ける方法があると確信しています。

+0

私に気になるのは、最も近い整数(下または*上*)に丸められる「丸い」です。元の数値より大きい整数では、小数点以下の桁があり、印刷された文字列全体が混乱します。 – coredump

+0

@coredump [truncateとftruncate](http://www.lispworks.com/documentation/HyperSpec/Body/f_floorc.htm)はゼロに向かって丸めます。それはあなたが望むような行動ですよね? –

+1

@Mars ROUND(およびTRUNCATE、前のコメントを参照)は複数の値を返します。違いを取る代わりに、 '(multiple-value-bind(quot rem)(truncate x)...)'を実行することができます。 –

5

Common Lispでは、私はcl-l10nを使用してロケールをサポートし、~Nを定義することをお勧めします。また、あなたがあなた自身をロールバックできます。

(defun money (stream number colonp atsignp &optional (decimal-places 2)) 
    (multiple-value-bind (integral decimal) (truncate number) 
    (format stream 
      (concatenate 'string 
         "~" 
         (and colonp ":") 
         (and atsignp "@") 
         "D" 
         "~0,vf") 
      integral 
      decimal-places 
      (abs decimal)))) 

(setf *read-default-float-format* 'double-float) 

(format nil "~2:@/money/" 123456789.123456789) 
=> "+123,456,789.12" 

、Clojureのために、~/はまだcl-formatでサポートされていないようですので、あなたは直接上記のコードを複製することはできません。 Javaライブラリを使用する方が早いかもしれません(例えば、this questionまたはthis other oneを参照)。

+0

シンプルな形式の文字列になると思いました! "〜:D $"などのようなもの。私はちょうどあなたがリンクしているそのJavaの答えを使用すると思います。ありがとう。 – madstap

+0

@madstap形式は、私たちがすべてをやっているわけではないことを忘れるかもしれないことがたくさんあります; – coredump

関連する問題