Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 86 additions & 109 deletions src/floatify.js
Original file line number Diff line number Diff line change
@@ -1,151 +1,128 @@
'use strict';
module.exports = class floatify {
toFloatFormat({ string, thousandsSeperator = '', decimalSeperator = '' }) {
let returnString = string;

var floatify = function floatify(str) {
var toFloatFormat = function toFloatFormat(str, ts, ds) {
var string = str;
var thousandsSeparator = ts || '';
var decimalSeparator = ds || '';
if (!!thousandsSeperator) {
returnString = returnString.replace(new RegExp(this.escapeForRegExp(thousandsSeperator), 'g'), '');
}

if (!!decimalSeperator) {
returnString = returnString.replace(new RegExp(this.escapeForRegExp(decimalSeperator), 'g'), '.');
}

return parseFloat(returnString);
}

thousandsSeparator = thousandsSeparator === '.' ? '\\.' : thousandsSeparator;
decimalSeparator = decimalSeparator === '.' ? '\\.' : decimalSeparator;
escapeForRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

string = thousandsSeparator !== '' ? string.replace(new RegExp(thousandsSeparator, 'g'), '') : string;
string = decimalSeparator !== '' ? string.replace(new RegExp(decimalSeparator, 'g'), '.') : string;
parseParts({ string, element, count }) {
const parts = string.split(element);

return parseFloat(string);
};
for (let i = 1; i < parts.length; i++) {
const left = {
index: i - 1,
value: parts[i - 1],
parsed: parseInt(parts[i - 1], 10)
};

var parseParts = function parseParts(str, ele, count) {
var string = str;
var element = ele;
var parts = string.split(element);
for (var i = 1; i < parts.length; i++) {
var left = parseInt(parts[i - 1], 10);
const part = parts[i];

if (parts[i].length === 0) {
if (part.length === 0) {
return Number.NaN;
} else if (parts[i].length === 3) {
if (parts[i - 1].length > 3 && parts.length - 1 !== i) {
} else if (part.length === 3) {
if (left.value.length > 3 && parts.length - 1 !== i) {
return Number.NaN;
}

if (
(left === 0 || isNaN(left) || parts[i - 1].length > 3)
} else if (
(left.parsed === 0 || isNaN(left.parsed) || left.value.length > 3)
&& parts.length - 1 === i
) {
return toFloatFormat(string, '', element);
return this.toFloatFormat({ string, thousandsSeperator: '', decimalSeperator: element });
}
} else if (i < parts.length - 1) {
// violation in midPart -> NaN
return Number.NaN;
} else {
// violation in end -> Could be decimalSeparator
if (count === 1) {
return toFloatFormat(string, '', element);
return this.toFloatFormat({ string, thousandsSeperator: '', decimalSeperator: element });
}
return Number.NaN;
}
}

return toFloatFormat(string, element, '');
};

var parse = function parse(str) {
var string = str;
var spacePos;
var spaceSplit;
var spaceCount;
var dotPos;
var commaPos;
var lDotPos;
var lCommaPos;
var dotCount;
var commaCount;

string = string.trim();

// 1st dot position
dotPos = string.indexOf('.');
// 1st comma position
commaPos = string.indexOf(',');
// 1st space position
spacePos = string.indexOf(' ');

if (dotPos + commaPos + spacePos === -3) {
// life is good, no separators
return toFloatFormat(string);
}
return this.toFloatFormat({ string, thousandsSeperator: element, decimalSeperator: '' });
}

// space count
spaceSplit = string.split(' ');
spaceCount = spaceSplit.length - 1;
parse(input) {
let string = input.trim();

if (spaceCount > 0) {
var first = spaceSplit.shift();
var last = spaceSplit.pop();
const hasSpace = string.includes(' ');
const spaceSplit = string.split(' ');
const spaceCount = spaceSplit.length - 1;

if (!string.match(/^(\d{1,3})?(\s\d{3})*([,\.]\d+)?$/)) {
return Number.NaN;
}
const hasDot = string.includes('.');
const dotPos = string.indexOf('.');
const dotCount = string.split('.').length - 1;
let lDotPos;

spaceSplit.unshift(first);
spaceSplit.push(last);
const hasComma = string.includes(',');
const commaPos = string.indexOf(',');
const commaCount = string.split(',').length - 1;
let lCommaPos;

string = spaceSplit.join('');
}

// dot count
dotCount = string.split('.').length - 1;
// comma count
commaCount = string.split(',').length - 1;
if (hasDot || hasComma || hasSpace) {
if (spaceCount > 0) {
const first = spaceSplit.shift();
const last = spaceSplit.pop();

if (dotPos !== -1 && commaPos !== -1) {
// format is using dot and comma
if (!string.match(/^(\d{1,3})?(\s\d{3})*([,\.]\d+)?$/)) {
return Number.NaN;
}

// last dot position
lDotPos = string.lastIndexOf('.');
// last comma position
lCommaPos = string.lastIndexOf(',');
spaceSplit.unshift(first);
spaceSplit.push(last);

// order of 1st dot -> comma must be same as last dot -> comma
// 123.123.123,123 -> ok 123.123,123.123 -> not ok
if (Math.sign(dotPos - commaPos) !== Math.sign(lDotPos - lCommaPos)) {
return Number.NaN;
string = spaceSplit.join('');
}

// check positions to guess the thousands separator
if (dotPos > commaPos && dotCount === 1) {
if (hasDot && hasComma) {
// format is using dot and comma

// last dot position
lDotPos = string.lastIndexOf('.');
// last comma position
lCommaPos = string.lastIndexOf(',');

// order of 1st dot -> comma must be same as last dot -> comma
// 123.123.123,123 -> ok 123.123,123.123 -> not ok
if (Math.sign(dotPos - commaPos) !== Math.sign(lDotPos - lCommaPos)) {
return Number.NaN;
}

// check positions to guess the thousands separator
if (dotPos > commaPos && dotCount === 1) {
// best guess: . is thousands separator and , is decimal point
return toFloatFormat(string, ',', '.');
}
return this.toFloatFormat({ string, thousandsSeperator: ',', decimalSeperator: '.' });
}

if (commaPos > dotPos && commaCount === 1) {
if (commaPos > dotPos && commaCount === 1) {
// best guess: , is thousands separator and . is decimal point
return toFloatFormat(string, '.', ',');
}

return Number.NaN;
}
return this.toFloatFormat({ string, thousandsSeperator: '.', decimalSeperator: ',' });
}

if (dotPos !== -1) {
return Number.NaN;
} else if (hasDot) {
// only dot(s) in format
return parseParts(string, '.', dotCount);
}

if (commaPos !== -1) {
return this.parseParts({ string, element: '.', count: dotCount });
} else if (hasComma) {
// only comma(s) in format
return parseParts(string, ',', commaCount);
return this.parseParts({ string, element: ',', count: commaCount });
}
}

return toFloatFormat(string);
};

return parse(str);
};

if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = floatify;
return this.toFloatFormat({ string });
}
exports.floatify = floatify;
}
};
5 changes: 5 additions & 0 deletions test/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"env": {
"mocha": true
}
}
12 changes: 6 additions & 6 deletions test/floatify.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use strict';

var floatify = require('../src/floatify.js');
var assert = require('assert');
const Floatify = require('../src/floatify.js');
const floatify = new Floatify();
const assert = require('assert');

const tests = [
{
Expand Down Expand Up @@ -289,13 +290,12 @@ tests.forEach((test) => {
it(`${assertion.input} gives ${assertion.expectation}`, () => {
if (Number.isNaN(assertion.expectation)) {
assert.strictEqual(
isNaN(floatify.floatify(assertion.input)),
isNaN(floatify.parse(assertion.input)),
true
);
return;
} else {
assert.equal(floatify.parse(assertion.input), assertion.expectation);
}

assert.equal(floatify.floatify(assertion.input), assertion.expectation);
});
});
});
Expand Down