50

When I parse this little piece of JSON:

{ "value" : 9223372036854775807 }

This is what I get:

{ hello: 9223372036854776000 } 

Is there any way to parse it properly?

ouflak
  • 2,458
  • 10
  • 44
  • 49
tartakynov
  • 2,768
  • 3
  • 26
  • 23
  • 1
    Maybe this is relevant http://stackoverflow.com/questions/307179/what-is-javascripts-max-int-whats-the-highest-integer-value-a-number-can-go-t – TGH Sep 12 '13 at 04:02
  • thanks, but I know integer precision in js, now I need to parse JSON from the C# web service which doesn't have a problem with large integers – tartakynov Sep 12 '13 at 04:08
  • It is possible to craft a regexp which would selectively transform all integers or only big integers or all numbers to strings presuming the JSON is valid. – Konstantin Pelepelin Dec 05 '19 at 19:03

4 Answers4

62

Not with built-in JSON.parse. You'll need to parse it manually and treat values as string (if you want to do arithmetics with them there is bignumber.js) You can use Douglas Crockford JSON.js library as a base for your parser.

EDIT2 ( 7 years after original answer ) - it might soon be possible to solve this using standard JSON api. Have a look at this TC39 proposal to add access to source string to a reviver function - https://github.com/tc39/proposal-json-parse-with-source

EDIT1: I created a package for you :)

var JSONbig = require('json-bigint');

var json = '{ "value" : 9223372036854775807, "v2": 123 }';
console.log('Input:', json);
console.log('');

console.log('node.js bult-in JSON:')
var r = JSON.parse(json);
console.log('JSON.parse(input).value : ', r.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSON.stringify(r));

console.log('\n\nbig number JSON:');
var r1 = JSONbig.parse(json);
console.log('JSON.parse(input).value : ', r1.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSONbig.stringify(r1));

Output:

Input: { "value" : 9223372036854775807, "v2": 123 }

node.js bult-in JSON:
JSON.parse(input).value :  9223372036854776000
JSON.stringify(JSON.parse(input)): {"value":9223372036854776000,"v2":123}


big number JSON:
JSON.parse(input).value :  9223372036854775807
JSON.stringify(JSON.parse(input)): {"value":9223372036854775807,"v2":123}
Andrey Sidorov
  • 24,905
  • 4
  • 62
  • 75
  • what is require? Is this from requireJS? – Vyache Feb 14 '14 at 04:33
  • kind of. Examples are meant to be run from node.js – Andrey Sidorov Feb 14 '14 at 04:41
  • Is there some way I can run this without node.js? Like in a browser environment? I can't get my head around this, I just need to change some long values and convert them into JSON object. – Vyache Feb 14 '14 at 04:58
  • You need to concatenate [index.js](https://github.com/sidorares/json-bigint/blob/master/index.js) + [stringify.js](https://github.com/sidorares/json-bigint/blob/master/stringify.js) + [bignumber.js](https://github.com/MikeMcl/bignumber.js/blob/master/bignumber.js) – Andrey Sidorov Feb 14 '14 at 06:14
  • 6
    I created bundle you can include to a web page using http://browserify.org/ - just add [this script](https://gist.github.com/sidorares/8996572) and use JSONbig.parse / JSONbig.stringify – Andrey Sidorov Feb 14 '14 at 06:19
  • @AndreySidorov Thanks for the module. However, parsing big numbers are causing object results - not numbers. I understand that - this is common logic to to handle these big numbers - but it requires extra care to call toString() on each value - which is a big difference. Any ideas on how to actually get the numeric values of big numbers (js)? – Alon Weissfeld Aug 11 '16 at 07:53
  • you can set a flag to save tham as strings - https://github.com/sidorares/json-bigint#optionsstoreasstring-boolean-default-false : `var JSONbigString = require('json-bigint')({"storeAsString": true});` – Andrey Sidorov Aug 11 '16 at 09:43
3

After searching something more clean - and finding only libs like jsonbigint, I just wrote my own solution. Is not the best, but it solves my problem. For those that are using Axios you can use it on transformResponse callback (this was my original problem - Axios parses the JSON and all bigInts cames wrong),

const jsonStr = `{"myBigInt":6028792033986383748, "someStr":"hello guys", "someNumber":123}`
const result = JSON.parse(jsonStr, (key, value) => {
 if (typeof value === 'number' && !Number.isSafeInteger(value)) {
     let strBig = jsonStr.match(new RegExp(`(?:"${key}":)(.*?)(?:,)`))[1] // get the original value using regex expression 
     return strBig //should be BigInt(strBig) - BigInt function is not working in this snippet
 }
 return value
   })
   console.log({
   "original": JSON.parse(jsonStr),
   "handled": result
   })
Graps
  • 49
  • 5
  • This answer would only work if all the keys were globally unique in the JSON. For example, `jsonStr = '[{"id":60287920339863888888,"name":"eights"},{"id":60287920339863999999,"name":"nines"}]'` would be parsed into the following wrong result: `{original: ..., handled: [{id: "60287920339863888888", name: "eights"}, {id: "60287920339863888888", name: "nines"}]}` – Arnie97 Jan 17 '22 at 09:08
  • `new RegExp(`(?:"${key}":)(.*?)(?=,|}|$)`)` This works for single object in json – Raja Rajendraprasath Jun 23 '22 at 10:21
0

A regular expression is difficult to get right for all cases.

Here is my attempt, but all I'm giving you is some extra test cases, not the solution. Likely you will want to replace a very specific attribute, and a more generic JSON parser (that handles separating out the properties, but leaves the numeric properties as strings) and then you can wrap that specific long number in quotes before continuing to parse into a javascript object.

let str = '{ "value" : -9223372036854775807, "value1" : "100", "strWNum": "Hi world: 42 is the answer", "arrayOfStrWNum": [":42, again.", "SOIs#1"], "arrayOfNum": [100,100,-9223372036854775807, 100, 42, 0, -1, 0.003] }'
let data = JSON.parse(str.replace(/([:][\s]*)(-?\d{1,90})([\s]*[\r\n,\}])/g, '$1"$2"$3'));
console.log(BigInt(data.value).toString());
console.log(data);
-1

you can use this code for change big numbers to strings and later use BigInt(data.value)

let str = '{ "value" : -9223372036854775807, "value1" : "100" }'
let data = JSON.parse(str.replace(/([^"^\d])(-?\d{1,90})([^"^\d])/g, '$1"$2"$3'));
console.log(BigInt(data.value).toString());
console.log(data);
Lucio M. Tato
  • 5,639
  • 2
  • 31
  • 30
  • 1
    You sure `"value": 9223372036854776000,` is the intended result? – connexo Sep 10 '19 at 10:35
  • 2
    While it's possible to create a regexp which quotes only numbers, the provided regexp gives incorrect result. Also, it would also break numbers which are already quoted or parts of quoted strings. – Konstantin Pelepelin Dec 05 '19 at 18:59
  • the correct regexp will be: /([0-9]{15,30}\.{0,1}[0-9]{0,})/g without the $ in the middle – scyrizales Nov 02 '20 at 07:51