st-json:write-json - avoid exponent markers for floats

Viewed 87
(st-json:write-json-to-string
  (st-json:read-json "{\"a\":0.1}"))

Output is not valid JSON:

"{\"a\":1.e-1}"

Desired output:

"{\"a\":0.1}"

I don't see any options or other arguments for write-json-to-string at https://marijnhaverbeke.nl/st-json/

I would still be ok if the number came out a little modified like .1 or 0.10

Update: There is a system variable for float format: "The printer uses *read-default-float-format* to guide the choice of exponent markers when printing floating-point numbers."

According to this example ...

(let ((*read-default-float-format* 'double-float))
  (read-from-string "(1.0 1.0e0 1.0s0 1.0f0 1.0d0 1.0L0)"))

==> (1.0d0 1.0d0 1.0 1.0 1.0d0 1.0d0)

The implementation I'm using (SBCL 2.0.11) has float formats F and D. http://www.lispworks.com/documentation/lw50/CLHS/Body/v_rd_def.htm

I'm not sure how "The printer uses *read-default-float-format* to guide the choice of exponent markers when printing floating-point numbers." ... Is there something wrong with my test below?

 (progn
   (setf *read-default-float-format* 'long-float)
   (princ(st-json:write-json-to-string (st-json:read-json "{\"a\":0.1}")))
   (setf *read-default-float-format* 'single-float)
   (princ(st-json:write-json-to-string (st-json:read-json "{\"a\":0.1}")))
   (setf *read-default-float-format* 'double-float)
   (princ(st-json:write-json-to-string (st-json:read-json "{\"a\":0.1}")))
   (setf *read-default-float-format* 'short-float)
   (princ(st-json:write-json-to-string (st-json:read-json "{\"a\":0.1}"))))
   
 {"a":1.e-1}{"a":1.e-1}{"a":1.e-1}{"a":1.e-1}
 ==> "{\"a\":1.e-1}"

Thanks in advance for any help!

1 Answers

It got nothing to do with *read-default-float-format*.

Using M-. in SLIME, I could see that write-json-to-string calls write-json which in turn calls write-json-element.

write-json-element is a generic function with different methods for different type. method for real is:

(defmethod write-json-element ((element real) stream)
  (format stream "~,,,,,,'eE" element))

That format string is standard Common Lisp, resulting in the behaviour you are seeing.

CL-USER> (format t "~,,,,,,'eE" 0.1)
1.e-1
NIL
CL-USER> 

I have no idea why author did that, but if you are stuck with st-json, Just redefine the method as (which will issue a re-definition warning, but ignore that):

(defmethod st-json:write-json-element ((element real) stream)
  (format stream "~F" element))

However, if you could switch to another library, take a look at jzon, it is in latest Quicklisp.

Related