Skip to content

Commit

Permalink
fix: parseNumber with custom format
Browse files Browse the repository at this point in the history
  • Loading branch information
danielkaradachki committed Jan 14, 2020
1 parent c9adfbb commit 395e705
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 53 deletions.
47 changes: 1 addition & 46 deletions src/numbers/custom-number-format.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,16 @@
import { CURRENCY, PERCENT, LIST_SEPARATOR, GROUP_SEPARATOR, CURRENCY_PLACEHOLDER, PERCENT_PLACEHOLDER, POINT, EMPTY } from '../common/constants';
import isNegativeZero from '../common/is-negative-zero';
import formatCurrencySymbol from './format-currency-symbol';
import groupInteger from './group-integer';
import round from '../common/round';

const PLACEHOLDER = "__??__";
import { setStyleOptions, setFormatLiterals, replaceLiterals } from './utils';

const SHARP = "#";
const ZERO = "0";

const literalRegExp = /(\\.)|(['][^']*[']?)|(["][^"]*["]?)/g;
const trailingZerosRegExp = /(\.(?:[0-9]*[1-9])?)0+$/g;
const trailingPointRegExp = /\.$/;
const commaRegExp = /\,/g;

function setFormatLiterals(formatOptions) {
let format = formatOptions.format;
if (format.indexOf("'") > -1 || format.indexOf("\"") > -1 || format.indexOf("\\") > -1) {
const literals = formatOptions.literals = [];
formatOptions.format = format.replace(literalRegExp, function(match) {
const quoteChar = match.charAt(0).replace("\\", EMPTY);
const literal = match.slice(1).replace(quoteChar, EMPTY);

literals.push(literal);

return PLACEHOLDER;
});
}
}

function trimTrailingZeros(value, lastZero) {
let trimRegex;

Expand Down Expand Up @@ -119,22 +101,6 @@ function setValueSpecificFormat(formatOptions) {
formatOptions.format = format;
}

function setStyleOptions(formatOptions, info) {
const format = formatOptions.format;

//multiply number if the format has percent
if (format.indexOf(PERCENT_PLACEHOLDER) !== -1) {
formatOptions.style = PERCENT;
formatOptions.symbol = info.numbers.symbols.percentSign;
formatOptions.number *= 100;
}

if (format.indexOf(CURRENCY_PLACEHOLDER) !== -1) {
formatOptions.style = CURRENCY;
formatOptions.symbol = formatCurrencySymbol(info);
}
}

function setGroupOptions(formatOptions) {
formatOptions.hasGroup = formatOptions.format.indexOf(GROUP_SEPARATOR) > -1;
if (formatOptions.hasGroup) {
Expand Down Expand Up @@ -187,17 +153,6 @@ function replaceStyleSymbols(number, style, symbol) {
return result;
}

function replaceLiterals(number, literals) {
let result = number;
if (literals) {
const length = literals.length;
for (let idx = 0; idx < length; idx++) {
result = result.replace(PLACEHOLDER, literals[idx]);
}
}
return result;
}

function replacePlaceHolders(formatOptions, info) {
const { start, end, negative, negativeZero, format, decimalIndex, lastZeroIndex, hasNegativeFormat, hasGroup } = formatOptions;
let number = formatOptions.number;
Expand Down
39 changes: 32 additions & 7 deletions src/numbers/parse-number.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { localeInfo, localeCurrency, currencyDisplays } from '../cldr';
import { PERCENT, NUMBER_PLACEHOLDER, CURRENCY_PLACEHOLDER, DEFAULT_LOCALE, EMPTY, POINT } from '../common/constants';
import { setStyleOptions, setFormatLiterals } from './utils';
import isNumber from '../common/is-number';
import isCurrencyStyle from './is-currency-style';
import formatOptions from './format-options';
import isString from '../common/is-string';

const exponentRegExp = /[eE][\-+]?[0-9]+/;
const nonBreakingSpaceRegExp = /\u00A0/g;
Expand Down Expand Up @@ -55,6 +57,19 @@ function cleanCurrencyNumber(value, info, format) {
};
}

function cleanLiterals(number, formatOptions) {
const literals = formatOptions.literals;
let result = number;

if (literals) {
for (let idx = 0; idx < literals.length; idx++) {
result = result.replace(literals[idx], EMPTY);
}
}

return result;
}

export default function parseNumber(value, locale = DEFAULT_LOCALE, format = {}) {
if (!value && value !== 0) {
return null;
Expand All @@ -68,29 +83,39 @@ export default function parseNumber(value, locale = DEFAULT_LOCALE, format = {})
const symbols = info.numbers.symbols;

let number = value.toString();
let formatOptions = format || {};
let isPercent;

if (isString(format)) {
formatOptions = { format: format };
setFormatLiterals(formatOptions);
number = cleanLiterals(number, formatOptions);

setStyleOptions(formatOptions, info);
}

if (formatOptions.style === PERCENT || number.indexOf(symbols.percentSign) > -1) {
number = number.replace(symbols.percentSign, EMPTY);
isPercent = true;
}

if (exponentRegExp.test(number)) {
number = parseFloat(number.replace(symbols.decimal, POINT));
return isNaN(number) ? null : number;
}

const { negative: negativeCurrency, number: currencyNumber } = cleanCurrencyNumber(number, info, formatOptions);
number = String(currencyNumber).trim();

const negativeSignIndex = number.indexOf("-");
if (negativeSignIndex > 0) {
return null;
}

let isNegative = negativeSignIndex > -1;
const { negative: negativeCurrency, number: newNumber } = cleanCurrencyNumber(number, info, format);

number = newNumber;
isNegative = negativeCurrency !== undefined ? negativeCurrency : isNegative;

if (format.style === PERCENT || number.indexOf(symbols.percentSign) > -1) {
number = number.replace(symbols.percentSign, EMPTY);
isPercent = true;
}

number = number.replace("-", EMPTY)
.replace(nonBreakingSpaceRegExp, " ")
.split(symbols.group.replace(nonBreakingSpaceRegExp, " ")).join(EMPTY)
Expand Down
47 changes: 47 additions & 0 deletions src/numbers/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { PERCENT_PLACEHOLDER, CURRENCY_PLACEHOLDER, CURRENCY, PERCENT, EMPTY } from '../common/constants';
import formatCurrencySymbol from './format-currency-symbol';

const literalRegExp = /(\\.)|(['][^']*[']?)|(["][^"]*["]?)/g;
const PLACEHOLDER = "__??__";

export function setStyleOptions(formatOptions, info) {
const format = formatOptions.format;

//multiply number if the format has percent
if (format.indexOf(PERCENT_PLACEHOLDER) !== -1) {
formatOptions.style = PERCENT;
formatOptions.symbol = info.numbers.symbols.percentSign;
formatOptions.number *= 100;
}

if (format.indexOf(CURRENCY_PLACEHOLDER) !== -1) {
formatOptions.style = CURRENCY;
formatOptions.symbol = formatCurrencySymbol(info);
}
}

export function setFormatLiterals(formatOptions) {
let format = formatOptions.format;
if (format.indexOf("'") > -1 || format.indexOf("\"") > -1 || format.indexOf("\\") > -1) {
const literals = formatOptions.literals = [];
formatOptions.format = format.replace(literalRegExp, function(match) {
const quoteChar = match.charAt(0).replace("\\", EMPTY);
const literal = match.slice(1).replace(quoteChar, EMPTY);

literals.push(literal);

return PLACEHOLDER;
});
}
}

export function replaceLiterals(number, literals) {
let result = number;
if (literals) {
const length = literals.length;
for (let idx = 0; idx < length; idx++) {
result = result.replace(PLACEHOLDER, literals[idx]);
}
}
return result;
}
15 changes: 15 additions & 0 deletions test/numbers.js
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,21 @@ describe('parseNumber', () => {
expect(parseNumber("-1 123 112,13 лв.", "bg")).toEqual(-1123112.13);
});

it("parses currency with custom format", () => {
expect(parseNumber("$12", 'en', '$#.#')).toEqual(12);
expect(parseNumber("-$12", 'en', '$#.#')).toEqual(-12);
});

it("parses percent with custom format", () => {
expect(parseNumber("% 12", 'en', '% #.#')).toEqual(0.12);
expect(parseNumber("% -12", 'en', '% #.#')).toEqual(-0.12);
});

it("parses number with custom format literals", () => {
expect(parseNumber("foo12", 'en', '"foo"#.#')).toEqual(12);
expect(parseNumber("T12", 'en', '\\T#.#')).toEqual(12);
});

it("parses currency numbers with negative format", () => {
loadCustom({ currencyPattern: "¤#,##0.00;(¤#,##0.00)", currencies: { USD: { symbol: "$" }}});
expect(parseNumber("($1,123,112.13)", "custom", { style: "currency", currency: "USD" })).toEqual(-1123112.13);
Expand Down

0 comments on commit 395e705

Please sign in to comment.