node.js - Is there any proper way to parse JSON with large numbers? (long, bigint, int64)
Asked Answered
G

4

53

When I parse this little piece of JSON:

{ "value" : 9223372036854775807 }

This is what I get:

{ value: 9223372036854776000 } 

Is there any way to parse it properly?

Grissel answered 12/9, 2013 at 3:59 Comment(3)
Maybe this is relevant #307679Manos
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 integersGrissel
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.Lignin
B
65

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}
Blanc answered 12/9, 2013 at 4:13 Comment(7)
what is require? Is this from requireJS?Hephaestus
kind of. Examples are meant to be run from node.jsBlanc
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.Hephaestus
You need to concatenate index.js + stringify.js + bignumber.jsBlanc
I created bundle you can include to a web page using browserify.org - just add this script and use JSONbig.parse / JSONbig.stringifyBlanc
@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)?Cynewulf
you can set a flag to save tham as strings - github.com/sidorares/… : var JSONbigString = require('json-bigint')({"storeAsString": true});Blanc
L
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
   })
Lannielanning answered 22/9, 2021 at 3:43 Comment(2)
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"}]}Carlitacarlo
new RegExp((?:"${key}":)(.*?)(?=,|}|$)) This works for single object in jsonTitivate
S
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);
Sparhawk answered 4/2, 2023 at 23:6 Comment(0)
H
-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);
Hohenzollern answered 3/10, 2018 at 11:26 Comment(3)
You sure "value": 9223372036854776000, is the intended result?Eufemiaeugen
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.Lignin
the correct regexp will be: /([0-9]{15,30}\.{0,1}[0-9]{0,})/g without the $ in the middleDashboard

© 2022 - 2024 — McMap. All rights reserved.