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

前端 未结 1 382
醉话见心
醉话见心 2020-12-17 01:12

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 exa

相关标签:
1条回答
  • 2020-12-17 01:36

    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);
    });
    
    0 讨论(0)
提交回复
热议问题