Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

alternative to JSON.parse() for maintaining decimal precision?

I'm calling JSON.parse() to parse a JSON string which has small decimals.

The precision of the decimals is not being maintained after parsing. For example, a value like 3.1e-7 is being returned instead of the actual decimal.

How can I deserialize a JSON string in ng2+ while maintaining decimal precision?

UPDATE

I was thinking about mapping out the values from the string and then setting the values manually to the object after JSON.parse() but when I set a different small decimal number as a property value, the same number formatting occurs. So is this problem not necessarily unique to JSON.parse() but to Javascript in general? Or does JSON.parse() somehow configure property types in a fixed way?

like image 219
user8570495 Avatar asked Dec 21 '17 00:12

user8570495


People also ask

Does JSON support decimal numbers?

A JSON document can contain numbers, written in decimal notation. The standard does not specify any type for these numbers – a number is just defined syntactically as a sequence of digits, optionally followed by a dot and some more digits.

Is JSON parse the opposite of JSON Stringify?

JSON. stringify() is the opposite of JSON. parse(), which converts JSON into Javascript objects.


1 Answers

As soon as you pass your JSON string through JSON.parse, you'll lose precision because of the way floating point math works. You'll need to store the number as an object designed for storing arbitrary-precision numbers, and you'll need to fiddle with the string itself before parsing it. The simplest way is with regexes. JSON is a context free grammar, and regexes work on regular grammars, so the warning applies:

WARNING: PARSING CFG WITH REGEX MAY SUMMON ZALGO

This regex should turn the numbers in your JSON into strings:

let stringedJSON = origJSON.replace(/:\s*([-+Ee0-9.]+)/g, ': "uniqueprefix$1"');

But I haven't tested it extensively and it definitely will screw things up if you have keys that are something like data:42.

Assuming it worked correctly, stringedJSON should now be something like {"foo": "uniqueprefix0.00000017", "bar": "an actual string"}. You can parse this with JSON.parse without losing precision, but uniqueprefix0.00000017 isn't what you want. JSON.parse can be called with an extra reviver argument, which transforms values passed to it before returning them. You can use this to convert your data back into a useful form:

let o = JSON.parse(stringedJSON, (key, value) => {
  // only changing strings
  if (typeof value !== 'string') return value;
  // only changing number strings
  if (!value.startsWith('uniqueprefix')) return value;
  // chop off the prefix
  value = value.slice('uniqueprefix'.length);
  // pick your favorite arbitrary-precision library
  return new Big(value);
});
like image 114
AuxTaco Avatar answered Oct 09 '22 09:10

AuxTaco