Chris Murphy
Chris Murphy

Reputation: 6509

Format a 'numeric' string as a number

I would like to format a 'numeric' string as a 'string number' in Clojure. This is the format mask:

"#,###,###,##0.00"

Given the string "9999.99" I would expect to receive back "9,999.99".

How would I do this in Clojure without resorting to writing a converter function i.e. using format or something similar?

Upvotes: 1

Views: 1202

Answers (3)

Taylor Wood
Taylor Wood

Reputation: 16194

You can use , in a format specifier:

(format "%,.2f" (float (clojure.edn/read-string "9999")))
=> "9,999.00"
(format "%,.2f" (Double/parseDouble "9999.126"))
=> "9,999.13"

Update to include bigdec example:

(format "%,.2f" (bigdec "9999999999999999.12"))
=> "9,999,999,999,999,999.12"

Upvotes: 1

It appears that in your problem domain the disadvantages and limitations of binary-base floating point (e.g. IEEE-754) are causing you some difficulty. Perhaps you should consider taking advantage of the BigDecimal support already built in to Clojure. In Clojure, the difference between a BigDecimal constant and a floating point constant is a single character; e.g. 1.2 is a Double, while 1.2M is a BigDecimal. The bigdec function can be used to convert things to BigDecimal on the fly. For example,

(format "%,.2f" (bigdec "9999999999999999.12"))

produces

"9,999,999,999,999,999.12"

as expected. Arithmetic functions such as *, +, -, and / also work as expected.

However, this doesn't solve your basic problem. If your format string doesn't follow Java/Clojure format string conventions you'll have to write a converter function.

Best of luck.

Upvotes: 4

Alan Thompson
Alan Thompson

Reputation: 29958

You can do this using NumberFormat. I also like the other answer (see the Java 10 Formatter docs for details):

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:import [java.text NumberFormat]
           [java.util Locale]))

(dotest
  (let [value (Double/valueOf "1234567.89")
        nf    (NumberFormat/getNumberInstance (Locale/US))
        s1a   (.format nf (.doubleValue value))
        s1b   (format "%,05.2f" value)]
    (spyx s1a)
    (spyx s1b))

s1a => "1,234,567.89"
s1b => "1,234,567.89"

  (let [value (Double/valueOf "1.2")
        nf    (NumberFormat/getNumberInstance (Locale/US))
        s1a   (.format nf (.doubleValue value))
        s1b   (format "%,05.2f" value)]
    (spyx s1a)
    (spyx s1b)))

s1a => "1.2"
s1b => "01.20"

Update

Here is how to do it for BigDecimal, using first Java interop and then a built-in Clojure function bigdec:

(format "%,05.2f" (BigDecimal. "9999999999999999.12")) => "9,999,999,999,999,999.12"
(format "%,05.2f" (bigdec      "9999999999999999.12")) => "9,999,999,999,999,999.12"

Upvotes: 1

Related Questions