Browse Source

Maintain precision on big numbers (>2^53 || <-2^53) when dynamicTyping is on (#694)

pull/696/head
haxxxton 6 years ago committed by Sergi Almacellas Abellana
parent
commit
76dc5a6d7f
  1. 2
      docs/docs.html
  2. 14
      papaparse.js
  3. 6
      tests/test-cases.js

2
docs/docs.html

@ -508,7 +508,7 @@ var csv = Papa.unparse({ @@ -508,7 +508,7 @@ var csv = Papa.unparse({
<code>dynamicTyping</code>
</td>
<td>
If true, numeric and boolean data will be converted to their type instead of remaining strings. Numeric data must conform to the definition of a decimal literal. European-formatted numbers must have commas and dots swapped. If also accepts an object or a function. If object it's values should be a boolean to indicate if dynamic typing should be applied for each column number (or header name if using headers). If it's a function, it should return a boolean value for each field number (or name if using headers) which will be passed as first argument.
If true, numeric and boolean data will be converted to their type instead of remaining strings. Numeric data must conform to the definition of a decimal literal. Numerical values greater than <code>2^53</code> or less than <code>-2^53</code> will not be converted to numbers to preserve precision. European-formatted numbers must have commas and dots swapped. If also accepts an object or a function. If object it's values should be a boolean to indicate if dynamic typing should be applied for each column number (or header name if using headers). If it's a function, it should return a boolean value for each field number (or name if using headers) which will be passed as first argument.
</td>
</tr>
<tr>

14
papaparse.js

@ -996,6 +996,8 @@ License: MIT @@ -996,6 +996,8 @@ License: MIT
function ParserHandle(_config)
{
// One goal is to minimize the use of regular expressions...
var MAX_FLOAT = Math.pow(2, 53);
var MIN_FLOAT = -MAX_FLOAT;
var FLOAT = /^\s*-?(\d*\.?\d+|\d+\.?\d*)(e[-+]?\d+)?\s*$/i;
var ISO_DATE = /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/;
var self = this;
@ -1123,6 +1125,16 @@ License: MIT @@ -1123,6 +1125,16 @@ License: MIT
return _config.skipEmptyLines === 'greedy' ? s.join('').trim() === '' : s.length === 1 && s[0].length === 0;
}
function testFloat(s) {
if (FLOAT.test(s)) {
var floatValue = parseFloat(s);
if (floatValue > MIN_FLOAT && floatValue < MAX_FLOAT) {
return true;
}
}
return false;
}
function processResults()
{
if (_results && _delimiterError)
@ -1190,7 +1202,7 @@ License: MIT @@ -1190,7 +1202,7 @@ License: MIT
return true;
else if (value === 'false' || value === 'FALSE')
return false;
else if (FLOAT.test(value))
else if (testFloat(value))
return parseFloat(value);
else if (ISO_DATE.test(value))
return new Date(value);

6
tests/test-cases.js

@ -815,11 +815,11 @@ var PARSE_TESTS = [ @@ -815,11 +815,11 @@ var PARSE_TESTS = [
}
},
{
description: "Dynamic typing converts numeric literals",
input: '1,2.2,1e3\r\n-4,-4.5,-4e-5\r\n-,5a,5-2',
description: "Dynamic typing converts numeric literals and maintains precision",
input: '1,2.2,1e3\r\n-4,-4.5,-4e-5\r\n-,5a,5-2\r\n16142028098527942586,9007199254740991,-9007199254740992',
config: { dynamicTyping: true },
expected: {
data: [[1, 2.2, 1000], [-4, -4.5, -0.00004], ["-", "5a", "5-2"]],
data: [[1, 2.2, 1000], [-4, -4.5, -0.00004], ["-", "5a", "5-2"], ["16142028098527942586", 9007199254740991, "-9007199254740992"]],
errors: []
}
},

Loading…
Cancel
Save