From ef1764cfd2962f848ebfe3ce0cab6a41efd37988 Mon Sep 17 00:00:00 2001 From: Patrick Henning Date: Wed, 21 Dec 2022 10:43:07 -0800 Subject: [PATCH 1/9] Locale-sensitive `numberFormat` and `parseNumber` --- src/arithmetic.ts | 86 +++++++++++--------------------- test/arithmetic-test.ts | 106 +++++++++++++++++++++++----------------- 2 files changed, 89 insertions(+), 103 deletions(-) diff --git a/src/arithmetic.ts b/src/arithmetic.ts index baa00e5..0a8ea58 100644 --- a/src/arithmetic.ts +++ b/src/arithmetic.ts @@ -36,74 +36,44 @@ export function sign(value: number, t = PRECISION) { // ----------------------------------------------------------------------------- // String Conversion -const NUM_REGEX = /(\d+)(\d{3})/; -const POWER_SUFFIX = ['', 'k', 'm', 'b', 't', 'q']; - -function addThousandSeparators(x: string) { - let [n, dec] = x.split('.'); - while (NUM_REGEX.test(n)) { - n = n.replace(NUM_REGEX, '$1,$2'); - } - return n + (dec ? `.${dec}` : ''); -} - -function addPowerSuffix(n: number, places = 6) { - if (!places) return `${n}`; - - // Trim short numbers to the appropriate number of decimal places. - const digits = (`${Math.abs(Math.floor(n))}`).length; - const chars = digits + (n < 0 ? 1 : 0); - if (chars <= places) return `${round(n, places - chars)}`; - - // Append a power suffix to longer numbers. - const x = Math.floor(Math.log10(Math.abs(n)) / 3); - const suffix = POWER_SUFFIX[x]; - const decimalPlaces = places - ((digits % 3) || 3) - (suffix ? 1 : 0) - (n < 0 ? 1 : 0); - return round(n / Math.pow(10, 3 * x), decimalPlaces) + suffix; -} - /** - * Converts a number to a clean string, by rounding, adding power suffixes, and - * adding thousands separators. `places` is the number of digits to show in the - * result. + * Converts a number to a clean string, by rounding, adding abbreviation suffixes, and + * adding grouping separators. `digits` is the number of numeric characters to + * show in the result, for example if `digits` is `3`, then for `n` = `10.12` the result + * will be `"10.1"`. + * Note: leading zeros are not counted towards how many digits to include; this means that + * if `digits` is `3`, then for `n` = `0.0123` the result will be `"0.0123"` + * Note: does not work for numbers > 10^21 or < 10^-6 */ -export function numberFormat(n: number, places = 0, separators = true) { - const str = addPowerSuffix(n, places).replace('-', '–'); - return separators ? addThousandSeparators(str) : str; +export function numberFormat(n: number, digits: number, separators = true, locale = 'en') { + const rawDigitsCount = n.toString().replace('.', '').replace('-', '').length; + const formatter = new Intl.NumberFormat(locale, { + useGrouping: separators, + maximumSignificantDigits: digits, + notation: digits < rawDigitsCount ? 'compact' : 'standard' + }); + if (locale === 'en') { + return formatter.format(n).replace('-', '–').toLowerCase(); + } else { + return formatter.format(n).replace('-', '–'); + } } -// Numbers like 0,123 are decimals, even though they match POINT_DECIMAL. -const SPECIAL_DECIMAL = /^-?0,[0-9]+$/; - -// Points as decimal points, Commas as 1k separators, allow starting . -const POINT_DECIMAL = /^-?([0-9]+(,[0-9]{3})*)?\.?[0-9]*$/; - -// Commas as decimal points, Points as 1k separators, don't allow starting , -const COMMA_DECIMAL = /^-?[0-9]+(\.[0-9]{3})*,?[0-9]*$/; - /** * Converts a number to a string, including . or , decimal points and * thousands separators. * @param {string} str * @returns {number} */ -export function parseNumber(str: string) { - str = str.replace(/^–/, '-').trim(); - if (!str || str.match(/[^0-9.,-]/)) return NaN; - - if (SPECIAL_DECIMAL.test(str)) { - return parseFloat(str.replace(/,/, '.')); - } - - if (POINT_DECIMAL.test(str)) { - return parseFloat(str.replace(/,/g, '')); - } - - if (COMMA_DECIMAL.test(str)) { - return parseFloat(str.replace(/\./g, '').replace(/,/, '.')); - } - - return NaN; +export function parseNumber(str: string, locale = 'en') { + // https://observablehq.com/@mbostock/localized-number-parsing + const parts = (new Intl.NumberFormat(locale)).formatToParts(11111111111.111111); + /* eslint-disable @typescript-eslint/no-non-null-assertion */ + const decimal = parts.find(p => p.type === 'decimal')!.value; + const group = parts.find(p => p.type === 'group')!.value; + /* eslint-enable @typescript-eslint/no-non-null-assertion */ + const neutral = str.replace('–', '-').replaceAll(group, '').replace(decimal, '.'); + return +neutral; } /** diff --git a/test/arithmetic-test.ts b/test/arithmetic-test.ts index 8f10c64..35a61dd 100644 --- a/test/arithmetic-test.ts +++ b/test/arithmetic-test.ts @@ -9,68 +9,84 @@ import {numberFormat, parseNumber, toWord} from '../src'; tape('numberFormat', (test) => { - test.equal(numberFormat(1234, 5), '1,234', ':: numberFormat(1234, 5)'); - test.equal(numberFormat(1234, 4), '1,234', ':: numberFormat(1234, 4)'); - test.equal(numberFormat(1234, 3), '1.2k', ':: numberFormat(1234, 3)'); - test.equal(numberFormat(1000, 3), '1k', ':: numberFormat(1000, 3)'); - test.equal(numberFormat(-1234, 6), '–1,234', ':: numberFormat(-1234, 6)'); - test.equal(numberFormat(-1234, 5), '–1,234', ':: numberFormat(-1234, 5)'); - test.equal(numberFormat(-1234, 4), '–1.2k', ':: numberFormat(-1234, 4)'); - test.equal(numberFormat(-1000, 4), '–1k', ':: numberFormat(-1000, 4)'); + test.equal(numberFormat(1234, 5, true), '1,234'); + test.equal(numberFormat(1234, 4, true), '1,234'); + test.equal(numberFormat(1234, 3, true), '1.23k'); + test.equal(numberFormat(12345.6, 3, true), '12.3k'); + test.equal(numberFormat(12345.6, 4, true), '12.35k'); + test.equal(numberFormat(-1234, 6, true), '–1,234'); + test.equal(numberFormat(-1234, 4, true), '–1,234'); + test.equal(numberFormat(-1234, 3, true), '–1.23k'); + test.equal(numberFormat(-1000, 3, true), '–1k'); - test.equal(numberFormat(10001, 5), '10,001', ':: numberFormat(10001, 5)'); - test.equal(numberFormat(10001, 4), '10k', ':: numberFormat(10001, 4)'); - test.equal(numberFormat(-10001, 6), '–10,001', ':: numberFormat(-10001, 6)'); - test.equal(numberFormat(-10001, 5), '–10k', ':: numberFormat(-10001, 5)'); - test.equal(numberFormat(100001, 6), '100,001', ':: numberFormat(100001, 6)'); - test.equal(numberFormat(100001, 5), '100k', ':: numberFormat(100001, 5)'); - test.equal(numberFormat(-100001, 7), '–100,001', ':: numberFormat(-100001, 7)'); - test.equal(numberFormat(-100001, 6), '–100k', ':: numberFormat(-100001, 6)'); - test.equal(numberFormat(1000001, 7), '1,000,001', ':: numberFormat(1000001, 7)'); - test.equal(numberFormat(1000001, 6), '1m', ':: numberFormat(1000001, 6)'); - test.equal(numberFormat(-1000001, 8), '–1,000,001', ':: numberFormat(-1000001, 8)'); - test.equal(numberFormat(-1000001, 7), '–1m', ':: numberFormat(-1000001, 7)'); + test.equal(numberFormat(10001, 5, true), '10,001'); + test.equal(numberFormat(10001, 4, true), '10k'); + test.equal(numberFormat(-10001, 5, true), '–10,001'); + test.equal(numberFormat(-10001, 4, true), '–10k'); + test.equal(numberFormat(100001, 6, true), '100,001'); + test.equal(numberFormat(100001, 5, true), '100k'); + test.equal(numberFormat(-100001, 6, true), '–100,001'); + test.equal(numberFormat(-100001, 5, true), '–100k'); + test.equal(numberFormat(1000001, 7, true), '1,000,001'); + test.equal(numberFormat(1000001, 6, true), '1m'); + test.equal(numberFormat(-1000001, 7, true), '–1,000,001'); + test.equal(numberFormat(-1000001, 6, true), '–1m'); - test.equal(numberFormat(0.1, 2), '0.1', ':: numberFormat(0.1, 2)'); - test.equal(numberFormat(0.1, 1), '0', ':: numberFormat(0.1, 1)'); - test.equal(numberFormat(-0.1, 3), '–0.1', ':: numberFormat(-0.1, 3)'); - test.equal(numberFormat(-0.1, 2), '0', ':: numberFormat(-0.1, 2)'); - test.equal(numberFormat(0.01, 3), '0.01', ':: numberFormat(0.01, 3)'); - test.equal(numberFormat(0.01, 2), '0', ':: numberFormat(0.01, 2)'); - test.equal(numberFormat(-0.01, 4), '–0.01', ':: numberFormat(-0.01, 4)'); - test.equal(numberFormat(-0.01, 3), '0', ':: numberFormat(-0.01, 3)'); - test.equal(numberFormat(0.001, 4), '0.001', ':: numberFormat(0.001, 4)'); - test.equal(numberFormat(0.001, 3), '0', ':: numberFormat(0.001, 3)'); - test.equal(numberFormat(-0.001, 5), '–0.001', ':: numberFormat(-0.001, 5)'); - test.equal(numberFormat(-0.001, 4), '0', ':: numberFormat(-0.001, 4)'); + test.equal(numberFormat(0.11, 2, true), '0.11'); + test.equal(numberFormat(0.11, 1, true), '0.1'); + test.equal(numberFormat(-0.11, 2, true), '–0.11'); + test.equal(numberFormat(-0.11, 1, true), '–0.1'); + test.equal(numberFormat(0.0111, 3, true), '0.0111'); + test.equal(numberFormat(0.011, 2, true), '0.011'); + test.equal(numberFormat(-0.011, 2, true), '–0.011'); + test.equal(numberFormat(-0.011, 1, true), '–0.01'); + test.equal(numberFormat(0.0011, 2, true), '0.0011'); + test.equal(numberFormat(0.0011, 1, true), '0.001'); + test.equal(numberFormat(-0.0011, 2, true), '–0.0011'); + test.equal(numberFormat(-0.0011, 1, true), '–0.001'); + test.equal(numberFormat(1000.11, 8, true, 'de'), '1.000,11'); + test.equal(numberFormat(1000.11, 8, true, 'es'), '1000,11'); + test.equal(numberFormat(10000.11, 8, true, 'es'), '10.000,11'); test.end(); }); tape('parseNumber', (test) => { test.equal(parseNumber('1234'), 1234); - test.equal(parseNumber('1.234,56'), 1234.56); + test.equal(parseNumber('1.234,56'), 1.23456); + test.equal(parseNumber('1,23456', 'de'), 1.23456); + test.equal(parseNumber('1,23456', 'es'), 1.23456); test.equal(parseNumber('1,234.56'), 1234.56); + test.equal(parseNumber('1.234,56', 'de'), 1234.56); + test.equal(parseNumber('1.234,56', 'es'), 1234.56); test.equal(parseNumber('1,234,567'), 1234567); - test.equal(parseNumber('1.234.567'), 1234567); + test.equal(parseNumber('1.234.567', 'de'), 1234567); + test.equal(parseNumber('1.234.567', 'es'), 1234567); test.equal(parseNumber('1,234.567'), 1234.567); - test.equal(parseNumber('1.234,567'), 1234.567); - test.equal(parseNumber('1.234'), 1.234); // ambiguous! - test.equal(parseNumber('1,234'), 1234); // ambiguous! - test.equal(parseNumber('0,123'), 0.123); // ambiguous! - test.equal(parseNumber('1,23'), 1.23); + test.equal(parseNumber('1.234,567', 'de'), 1234.567); + test.equal(parseNumber('1.234,567', 'es'), 1234.567); + test.equal(parseNumber('1.234'), 1.234); + test.equal(parseNumber('1,234', 'de'), 1.234); + test.equal(parseNumber('1,234', 'es'), 1.234); + test.equal(parseNumber('1,234'), 1234); + test.equal(parseNumber('1.234', 'de'), 1234); + test.equal(parseNumber('1.234', 'es'), 1234); + test.equal(parseNumber('0.123'), 0.123); + test.equal(parseNumber('0,123', 'de'), 0.123); + test.equal(parseNumber('0,123', 'es'), 0.123); + test.equal(parseNumber('1.23'), 1.23); + test.equal(parseNumber('1,23'), 123); + test.equal(parseNumber('1,23', 'de'), 1.23); + test.equal(parseNumber('1.23', 'de'), 123); test.equal(parseNumber('1.2345'), 1.2345); test.equal(parseNumber('.123'), 0.123); test.equal(parseNumber('-123'), -123); test.equal(parseNumber('–123'), -123); - test.equal(parseNumber('-123,456'), -123456); // ambiguous! - test.equal(parseNumber('-123.456'), -123.456); // ambiguous! - - test.ok(isNaN(parseNumber('1,2345,678'))); + test.notOk(isNaN(parseNumber('1,2345,678'))); test.ok(isNaN(parseNumber('1.2345.678'))); - test.ok(isNaN(parseNumber('1,2345.678'))); - test.ok(isNaN(parseNumber('1.2345,678'))); + test.notOk(isNaN(parseNumber('1,2345.678'))); + test.notOk(isNaN(parseNumber('1.2345,678'))); test.ok(isNaN(parseNumber('1.234,56A'))); test.ok(isNaN(parseNumber('123A456'))); From 381b4ff70c9a3ee31942a7dc17509d10e30250b1 Mon Sep 17 00:00:00 2001 From: Patrick Henning Date: Wed, 28 Dec 2022 14:56:28 -0800 Subject: [PATCH 2/9] Avoid use of `replaceAll` for node 14 compat --- src/arithmetic.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/arithmetic.ts b/src/arithmetic.ts index 0a8ea58..e17a989 100644 --- a/src/arithmetic.ts +++ b/src/arithmetic.ts @@ -72,7 +72,11 @@ export function parseNumber(str: string, locale = 'en') { const decimal = parts.find(p => p.type === 'decimal')!.value; const group = parts.find(p => p.type === 'group')!.value; /* eslint-enable @typescript-eslint/no-non-null-assertion */ - const neutral = str.replace('–', '-').replaceAll(group, '').replace(decimal, '.'); + const neutral = + str + .replace('–', '-') + .replace(new RegExp(`\\${group}`, 'g'), '') + .replace(decimal, '.'); return +neutral; } From a0fc526a06a55c4b1a954927a9526da77cd2c3e1 Mon Sep 17 00:00:00 2001 From: Patrick Henning Date: Wed, 28 Dec 2022 15:14:35 -0800 Subject: [PATCH 3/9] Handle usage where number of digits not specified --- src/arithmetic.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arithmetic.ts b/src/arithmetic.ts index e17a989..d8e07c3 100644 --- a/src/arithmetic.ts +++ b/src/arithmetic.ts @@ -45,8 +45,9 @@ export function sign(value: number, t = PRECISION) { * if `digits` is `3`, then for `n` = `0.0123` the result will be `"0.0123"` * Note: does not work for numbers > 10^21 or < 10^-6 */ -export function numberFormat(n: number, digits: number, separators = true, locale = 'en') { +export function numberFormat(n: number, digits?: number, separators = true, locale = 'en') { const rawDigitsCount = n.toString().replace('.', '').replace('-', '').length; + if (digits === undefined) digits = rawDigitsCount; const formatter = new Intl.NumberFormat(locale, { useGrouping: separators, maximumSignificantDigits: digits, From db6a38ced6ac104dea4f7b4bd66d0117202aaede Mon Sep 17 00:00:00 2001 From: Patrick Henning Date: Wed, 28 Dec 2022 15:21:14 -0800 Subject: [PATCH 4/9] Adjust parameter ergonomics --- src/arithmetic.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/arithmetic.ts b/src/arithmetic.ts index d8e07c3..73f008e 100644 --- a/src/arithmetic.ts +++ b/src/arithmetic.ts @@ -45,13 +45,16 @@ export function sign(value: number, t = PRECISION) { * if `digits` is `3`, then for `n` = `0.0123` the result will be `"0.0123"` * Note: does not work for numbers > 10^21 or < 10^-6 */ -export function numberFormat(n: number, digits?: number, separators = true, locale = 'en') { +export function numberFormat( + n: number, digits: number | 'auto' = 'auto', + separators: boolean | 'auto' = 'auto', + locale = 'en' +) { const rawDigitsCount = n.toString().replace('.', '').replace('-', '').length; - if (digits === undefined) digits = rawDigitsCount; const formatter = new Intl.NumberFormat(locale, { - useGrouping: separators, - maximumSignificantDigits: digits, - notation: digits < rawDigitsCount ? 'compact' : 'standard' + useGrouping: separators === 'auto' ? undefined : separators, + maximumSignificantDigits: digits === 'auto' ? undefined : digits, + notation: digits !== 'auto' && digits < rawDigitsCount ? 'compact' : 'standard' }); if (locale === 'en') { return formatter.format(n).replace('-', '–').toLowerCase(); From 34fc7ed458dfaf5e4139e8413dee1d1458c90162 Mon Sep 17 00:00:00 2001 From: Patrick Henning Date: Wed, 28 Dec 2022 15:33:57 -0800 Subject: [PATCH 5/9] Add locale parameter for XNumber `toString` --- src/xnumber.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/xnumber.ts b/src/xnumber.ts index dbb3ad0..f3fab25 100755 --- a/src/xnumber.ts +++ b/src/xnumber.ts @@ -27,8 +27,9 @@ export class XNumber { return this.value; } - toString(precision = 4) { - let num = numberFormat(this.num, precision); + toString(precision?: number | 'auto', locale = 'en') { + if (precision === 'auto' || precision === undefined) precision = 4; + let num = numberFormat(this.num, precision, 'auto', locale); let unit = this.unit || ''; const den = this.den ? `/${numberFormat(this.den, precision)}` : ''; if (num === '0') unit = ''; From ad473f1e53b55097aa11798e88b9cf8272cbed42 Mon Sep 17 00:00:00 2001 From: Patrick Henning Date: Thu, 5 Jan 2023 13:56:19 -0800 Subject: [PATCH 6/9] Accept options for Intl.NumberFormat --- src/arithmetic.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/arithmetic.ts b/src/arithmetic.ts index 73f008e..c58db69 100644 --- a/src/arithmetic.ts +++ b/src/arithmetic.ts @@ -48,13 +48,15 @@ export function sign(value: number, t = PRECISION) { export function numberFormat( n: number, digits: number | 'auto' = 'auto', separators: boolean | 'auto' = 'auto', - locale = 'en' + locale = 'en', + otherFormatterOptions?: Intl.NumberFormatOptions ) { const rawDigitsCount = n.toString().replace('.', '').replace('-', '').length; const formatter = new Intl.NumberFormat(locale, { useGrouping: separators === 'auto' ? undefined : separators, maximumSignificantDigits: digits === 'auto' ? undefined : digits, - notation: digits !== 'auto' && digits < rawDigitsCount ? 'compact' : 'standard' + notation: digits !== 'auto' && digits < rawDigitsCount ? 'compact' : 'standard', + ...otherFormatterOptions }); if (locale === 'en') { return formatter.format(n).replace('-', '–').toLowerCase(); From f11764af87e3dd0db1f9a5eabe4d3b2f6e6c4d4e Mon Sep 17 00:00:00 2001 From: Patrick Henning Date: Tue, 10 Jan 2023 20:55:43 -0800 Subject: [PATCH 7/9] Small code format adjustment --- src/arithmetic.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arithmetic.ts b/src/arithmetic.ts index c58db69..0cfa9a8 100644 --- a/src/arithmetic.ts +++ b/src/arithmetic.ts @@ -46,7 +46,8 @@ export function sign(value: number, t = PRECISION) { * Note: does not work for numbers > 10^21 or < 10^-6 */ export function numberFormat( - n: number, digits: number | 'auto' = 'auto', + n: number, + digits: number | 'auto' = 'auto', separators: boolean | 'auto' = 'auto', locale = 'en', otherFormatterOptions?: Intl.NumberFormatOptions From e91bdb1dac54935a6d259de74737b5904b266b7b Mon Sep 17 00:00:00 2001 From: pjhenning Date: Thu, 8 Feb 2024 16:24:56 -0800 Subject: [PATCH 8/9] Document --- src/arithmetic.ts | 28 +++++++++++++++++++++++++--- src/xnumber.ts | 10 ++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/arithmetic.ts b/src/arithmetic.ts index 3961081..ae9e9fa 100644 --- a/src/arithmetic.ts +++ b/src/arithmetic.ts @@ -36,6 +36,22 @@ export function sign(value: number, t = PRECISION) { // ----------------------------------------------------------------------------- // String Conversion +/** Get total number of digits (numeric chars) */ +function getRawDigitsCount(of: number) { + const digit = /\d/g; + return of.toString().match(digit)?.length ?? 0; +} + +function getIntegerDigitsCount(of: number) { + return getRawDigitsCount(Math.trunc(of)); +} + +/** Get total number of zeroes */ +function getZeroesCount(of: number) { + const digit = /0/g; + return of.toString().match(digit)?.length ?? 0; +} + /** * Converts a number to a clean string, by rounding, adding abbreviation suffixes, and * adding grouping separators. `digits` is the number of numeric characters to @@ -52,11 +68,12 @@ export function numberFormat( locale = 'en', otherFormatterOptions?: Intl.NumberFormatOptions ) { - const rawDigitsCount = n.toString().replace('.', '').replace('-', '').length; const formatter = new Intl.NumberFormat(locale, { useGrouping: separators === 'auto' ? undefined : separators, maximumSignificantDigits: digits === 'auto' ? undefined : digits, - notation: digits !== 'auto' && digits < rawDigitsCount ? 'compact' : 'standard', + // If the display digits count is less than the integer digits count then we want to use an abbreviated format. + // For example: given `n = 12343.2` and `digits = 4`, we would like a result of `'12.34K'` rather than `'12,340'`. + notation: digits !== 'auto' && digits < getIntegerDigitsCount(n) ? 'compact' : 'standard', ...otherFormatterOptions }); if (locale === 'en') { @@ -69,7 +86,12 @@ export function numberFormat( export function scientificFormat(value: number, places = 6) { const abs = Math.abs(value); if (isBetween(abs, Math.pow(10, -places), Math.pow(10, places))) { - return numberFormat(value, places); + if (abs >= 1) { + return numberFormat(value, places); + } else { + const digitsDelta = places - getZeroesCount(value); + return numberFormat(value, digitsDelta > 0 ? digitsDelta : places); + } } // TODO Decide how we want to handle these special cases diff --git a/src/xnumber.ts b/src/xnumber.ts index 12e0bfe..f07e343 100755 --- a/src/xnumber.ts +++ b/src/xnumber.ts @@ -61,12 +61,14 @@ export class XNumber { } } - toString(precision: number | 'auto' = 4, locale = 'en') { + toString(digits: number | 'auto' = 4, locale = 'en') { + // If this is a fraction or has a unit then we do not want separators; otherwise we go with the locale default const separators = (this.den || this.unit) ? false : 'auto'; - const actualPrecision = this.den ? 0 : precision; - let num = numberFormat(this.num, actualPrecision, separators, locale); + // If this is a fraction then we do not accept a manually specified value for the length of the numerator + const actualDigits = this.den ? 'auto' : digits; + let num = numberFormat(this.num, actualDigits, separators, locale); let unit = this.unit || ''; - const den = this.den ? `/${numberFormat(this.den, precision)}` : ''; + const den = this.den ? `/${numberFormat(this.den, 'auto', false)}` : ''; if (num === '0') unit = ''; if (unit === 'π' && !this.den && (num === '1' || num === '–1')) num = num.replace('1', ''); return `${num}${den}${unit}`; From c1951c639b32161adaa30bdcc510b6d205fb7234 Mon Sep 17 00:00:00 2001 From: pjhenning Date: Thu, 8 Feb 2024 17:44:39 -0800 Subject: [PATCH 9/9] Adjust tests --- test/arithmetic-test.ts | 6 +++--- test/xnumber-test.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/arithmetic-test.ts b/test/arithmetic-test.ts index 91b7a8e..aae3167 100644 --- a/test/arithmetic-test.ts +++ b/test/arithmetic-test.ts @@ -44,9 +44,9 @@ tape('numberFormat', (test) => { test.equal(numberFormat(0.0011, 1, true), '0.001', ':: numberFormat(0.001, 1, true)'); test.equal(numberFormat(-0.0011, 2, true), '–0.0011', ':: numberFormat(-0.0011, 2, true)'); test.equal(numberFormat(-0.0011, 1, true), '–0.001', ':: numberFormat(-0.0011, 1, true)'); - test.equal(numberFormat(1000.11, 8, true, 'de'), '1.000,11', ":: numberFormat(1000.11, 8, true, 'de')"); - test.equal(numberFormat(1000.11, 8, true, 'es'), '1000,11', ":: numberFormat(1000.11, 8, true, 'es')"); - test.equal(numberFormat(10000.11, 8, true, 'es'), '10.000,11', ":: numberFormat(10000.11, 8, true, 'es')"); + test.equal(numberFormat(1000.11, 8, 'auto', 'de'), '1.000,11', `:: numberFormat(1000.11, 8, true, 'de')`); + test.equal(numberFormat(1000.11, 8, 'auto', 'es'), '1000,11', `:: numberFormat(1000.11, 8, true, 'es')`); + test.equal(numberFormat(10000.11, 8, 'auto', 'es'), '10.000,11', `:: numberFormat(10000.11, 8, true, 'es')`); test.equal(scientificFormat(123123123, 6), '1.231 × 10^8'); test.equal(scientificFormat(123123, 6), '123,123'); diff --git a/test/xnumber-test.ts b/test/xnumber-test.ts index 96ef451..3fa5efc 100644 --- a/test/xnumber-test.ts +++ b/test/xnumber-test.ts @@ -134,7 +134,7 @@ tape('Scientific notation', (test) => { test.deepEqual(expr(0.000002, 'scientific'), '2 × 10^(-6)'); test.deepEqual(expr(0.00012, 'scientific'), '1.2 × 10^(-4)'); test.deepEqual(expr(1234.3, 'scientific'), '"1,234"'); - test.deepEqual(expr(12343.2, 'decimal'), '"12.3k"'); + test.deepEqual(expr(12343.2, 'decimal'), '"12.34k"'); test.deepEqual(expr(12343.2, 'scientific'), '1.234 × 10^4'); test.deepEqual(expr(123432.1, 'scientific'), '1.234 × 10^5'); test.end();