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?
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.
JSON. stringify() is the opposite of JSON. parse(), which converts JSON into Javascript objects.
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);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With