From 6dc41a3ca4532b968c465c46ec0f5784b3e08067 Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Mon, 6 May 2024 06:15:25 +0800 Subject: [PATCH] Organize methods Put common English methods to en/common. --- .../src/systems/en-UK/long-count/stringify.ts | 250 +++-------------- .../systems/en-US/short-count/stringify.ts | 252 +++--------------- packages/core/src/systems/en/common.ts | 168 +++++++++++- 3 files changed, 254 insertions(+), 416 deletions(-) diff --git a/packages/core/src/systems/en-UK/long-count/stringify.ts b/packages/core/src/systems/en-UK/long-count/stringify.ts index a6432f0..a7a7b54 100644 --- a/packages/core/src/systems/en-UK/long-count/stringify.ts +++ b/packages/core/src/systems/en-UK/long-count/stringify.ts @@ -6,158 +6,23 @@ import { } from '../../../common'; import { numberToExponential } from '../../../exponent'; import { - CENTILLIONS_PREFIXES, - CentillionsPrefix, - DECILLIONS_PREFIXES, - DecillionsPrefix, DECIMAL_POINT, - EMPTY_GROUP_DIGITS, - EXPONENT_DELIMITER, GROUP_SEPARATOR, GROUPING_SYMBOL, - HUNDRED, + EXPONENT_DELIMITER, + DECILLIONS_PREFIXES, + EMPTY_GROUP_DIGITS, ILLION_SUFFIX, MILLIA_PREFIX, - MILLIONS_PREFIXES, - MILLIONS_SPECIAL_PREFIXES, - MillionsPrefix, - MillionsSpecialPrefix, - NEGATIVE, - ONES, - OnesName, - SHORT_MILLIA_DELIMITER, SHORT_MILLIA_ILLION_DELIMITER, T_AFFIX, - TEN_PLUS_ONES, - TenPlusOnesName, - TENS, - TENS_ONES_SEPARATOR, - TensName, + SHORT_MILLIA_DELIMITER, + SHORT_MILLIA_ILLION_DELIMITER, + T_AFFIX, THOUSAND, + makeHundredsName, + makeCentillionsPrefix, + repeatString, + StringifyGroupsOptions, } from '../../en/common'; -/** - * Builds a name for numbers in tens and ones. - * @param tens - Tens digit. - * @param ones - Ones digit. - * @param addTensDashes - Whether to add dashes between the tens and ones. - * @returns string The name for the number. - */ -const makeTensName = (tens: number, ones: number, addTensDashes: boolean) => { - if (tens === 0) { - return ONES[ones]; - } - - if (tens === 1) { - return TEN_PLUS_ONES[ones] as unknown as TenPlusOnesName; - } - - if (ones === 0) { - return TENS[tens]; - } - - return `${TENS[tens] as Exclude}${addTensDashes ? TENS_ONES_SEPARATOR : ' '}${ONES[ones] as Exclude}` as const; -}; - -/** - * Builds a name for numbers in hundreds, tens, and ones. - * @param hundreds - Hundreds digit. - * @param tens - Tens digit. - * @param ones - Ones digit. - * @param addTensDashes - Whether to add dashes between the tens and ones. - * @returns string The name for the number. - */ -const makeHundredsName = (hundreds: number, tens: number, ones: number, addTensDashes: boolean) => { - if (hundreds === 0) { - return makeTensName(tens, ones, addTensDashes); - } - - if (tens === 0 && ones === 0) { - return `${ONES[hundreds]} ${HUNDRED}` as const; - } - - return `${ONES[hundreds]} ${HUNDRED} ${makeTensName(tens, ones, addTensDashes)}` as const; -}; - -/** - * Builds a name for numbers in the millions. - * @param millions - Millions digit. - * @param currentMillia - Current millia- group. - * @param longestMilliaCount - Number of millia- groups. - * @returns string The millions prefix. - */ -const makeMillionsPrefix = ( - millions: number, - currentMillia: GroupPlace, - longestMilliaCount: GroupPlace, -) => { - if (currentMillia === BigInt(0) && longestMilliaCount === BigInt(0)) { - return MILLIONS_SPECIAL_PREFIXES[millions] as MillionsSpecialPrefix; - } - - return MILLIONS_PREFIXES[millions] as MillionsPrefix; -}; - -/** - * Builds a name for numbers in the decillions. - * @param decillions - Decillions digit. - * @param millions - Millions digit. - * @param currentMillia - Current millia- group. - * @param longestMilliaCount - Number of millia- groups. - * @returns string The decillions prefix. - */ -const makeDecillionsPrefix = ( - decillions: number, - millions: number, - currentMillia: GroupPlace, - longestMilliaCount: GroupPlace, -) => { - if (decillions === 0) { - return makeMillionsPrefix(millions, currentMillia, longestMilliaCount); - } - - const onesPrefix = MILLIONS_PREFIXES[millions] as MillionsPrefix; - const tensName = DECILLIONS_PREFIXES[decillions] as DecillionsPrefix; - return `${onesPrefix}${tensName}` as const; -}; - -/** - * Builds a name for numbers in the centillions. - * @param centillions - Centillions digit. - * @param decillions - Decillions digit. - * @param millions - Millions digit. - * @param currentMillia - Current millia- group. - * @param longestMilliaCount - Number of millia- groups. - * @returns string The centillions prefix. - */ -const makeCentillionsPrefix = ( - centillions: number, - decillions: number, - millions: number, - currentMillia: GroupPlace, - longestMilliaCount: GroupPlace, -) => { - if (centillions === 0) { - return makeDecillionsPrefix(decillions, millions, currentMillia, longestMilliaCount); - } - - const onesPrefix = MILLIONS_PREFIXES[millions] as MillionsPrefix; - const tensName = DECILLIONS_PREFIXES[decillions] as DecillionsPrefix; - const hundredsName = CENTILLIONS_PREFIXES[centillions] as CentillionsPrefix; - return `${hundredsName}${onesPrefix}${decillions > 0 ? tensName : ''}` as const; -}; - -/** - * Repeats a string a given number of times. - * @param s - String to repeat. - * @param count - Number of times to repeat the string. - * @returns string The repeated string. - */ -const repeatString = (s: string, count: GroupPlace) => { - let result = ''; - for (let i = BigInt(0); i < count; i += BigInt(1)) { - result += s; - } - return result; -}; - const getGroupName = (place: GroupPlace, shortenMillia: boolean) => { if (place === BigInt(0)) { return '' as const; @@ -240,48 +105,6 @@ const getGroupName = (place: GroupPlace, shortenMillia: boolean) => { return `${isThousand ? `${THOUSAND} ` : ''}${groupGroups}${ILLION_SUFFIX}` as const; }; -export interface StringifyGroupsOptions { - /** - * Whether to add dashes between tens and ones (e.g. "sixty-nine"). - */ - addTensDashes?: boolean; - /** - * Use "millia^2-tillion" instead of "milliamilliatillion". - */ - shortenMillia?: boolean; -} - -/** - * Creates a group string. - * @param groups - The groups. - * @param options - Options to use when creating the group. - * @returns string[] The groups represented into strings. - */ -export const stringifyGroups = (groups: Group[], options?: StringifyGroupsOptions): string[] => { - const filteredGroups = groups.filter(([digits, place]) => ( - place === BigInt(0) || digits !== EMPTY_GROUP_DIGITS - )); - - return filteredGroups.map( - ([group, place]) => { - const makeHundredsArgs = group - .padStart(3, '0') - .split('') - .map((s) => Number(s)) as [number, number, number]; - - const groupDigitsName = makeHundredsName( - ...makeHundredsArgs, - options?.addTensDashes ?? true, - ); - const groupName = getGroupName(place, options?.shortenMillia ?? false); - if (groupName.length > 0) { - return `${groupDigitsName} ${groupName}`; - } - return groupDigitsName; - }, - ); -}; - /** * Group a number string into groups of three digits, starting from the decimal point. * @param value - The number string to group. @@ -319,27 +142,40 @@ export const splitIntoGroups = (value: string): Group[] => { ); }; -export interface MergeTokensOptions { - oneGroupPerLine?: boolean; -} - /** - * Formats the final tokenized string. - * @param tokens - The tokens to finalize. - * @param options - The options to use. + * Creates a group string. + * @param groups - The groups. + * @param options - Options to use when creating the group. + * @returns string[] The groups represented into strings. */ -export const mergeTokens = (tokens: string[], options?: MergeTokensOptions) => ( - tokens - .map((t) => t.trim()) - .join(options?.oneGroupPerLine ? '\n' : GROUP_SEPARATOR) - .trim() -); +export const stringifyGroups = (groups: Group[], options?: StringifyGroupsOptions): string[] => { + const filteredGroups = groups.filter(([digits, place]) => ( + place === BigInt(0) || digits !== EMPTY_GROUP_DIGITS + )); -/** - * Makes a negative string. - * @param s - The string to make negative. - */ -export const makeNegative = (s: string) => { - const negativePrefix = `${NEGATIVE} `; - return s.startsWith(negativePrefix) ? s.slice(negativePrefix.length) : `${negativePrefix}${s}`; + return filteredGroups.map( + ([group, place]) => { + const makeHundredsArgs = group + .padStart(3, '0') + .split('') + .map((s) => Number(s)) as [number, number, number]; + + const groupDigitsName = makeHundredsName( + ...makeHundredsArgs, + options?.addTensDashes ?? true, + ); + const groupName = getGroupName(place, options?.shortenMillia ?? false); + if (groupName.length > 0) { + return `${groupDigitsName} ${groupName}`; + } + return groupDigitsName; + }, + ); }; + +export { + StringifyGroupsOptions, + MergeTokensOptions, + mergeTokens, + makeNegative, +} from '../../en/common'; diff --git a/packages/core/src/systems/en-US/short-count/stringify.ts b/packages/core/src/systems/en-US/short-count/stringify.ts index 3b0d8c3..9060c08 100644 --- a/packages/core/src/systems/en-US/short-count/stringify.ts +++ b/packages/core/src/systems/en-US/short-count/stringify.ts @@ -6,158 +6,23 @@ import { } from '../../../common'; import { numberToExponential } from '../../../exponent'; import { - CENTILLIONS_PREFIXES, - CentillionsPrefix, - DECILLIONS_PREFIXES, - DecillionsPrefix, DECIMAL_POINT, - EMPTY_GROUP_DIGITS, - EXPONENT_DELIMITER, GROUP_SEPARATOR, GROUPING_SYMBOL, - HUNDRED, + EXPONENT_DELIMITER, + DECILLIONS_PREFIXES, + EMPTY_GROUP_DIGITS, ILLION_SUFFIX, MILLIA_PREFIX, - MILLIONS_PREFIXES, - MILLIONS_SPECIAL_PREFIXES, - MillionsPrefix, - MillionsSpecialPrefix, - NEGATIVE, - ONES, - OnesName, - SHORT_MILLIA_DELIMITER, SHORT_MILLIA_ILLION_DELIMITER, T_AFFIX, - TEN_PLUS_ONES, - TenPlusOnesName, - TENS, - TENS_ONES_SEPARATOR, - TensName, + SHORT_MILLIA_DELIMITER, + SHORT_MILLIA_ILLION_DELIMITER, + T_AFFIX, THOUSAND, + makeHundredsName, + makeCentillionsPrefix, + repeatString, + StringifyGroupsOptions, } from '../../en/common'; -/** - * Builds a name for numbers in tens and ones. - * @param tens - Tens digit. - * @param ones - Ones digit. - * @param addTensDashes - Whether to add dashes between the tens and ones. - * @returns string The name for the number. - */ -const makeTensName = (tens: number, ones: number, addTensDashes: boolean) => { - if (tens === 0) { - return ONES[ones]; - } - - if (tens === 1) { - return TEN_PLUS_ONES[ones] as unknown as TenPlusOnesName; - } - - if (ones === 0) { - return TENS[tens]; - } - - return `${TENS[tens] as Exclude}${addTensDashes ? TENS_ONES_SEPARATOR : ' '}${ONES[ones] as Exclude}` as const; -}; - -/** - * Builds a name for numbers in hundreds, tens, and ones. - * @param hundreds - Hundreds digit. - * @param tens - Tens digit. - * @param ones - Ones digit. - * @param addTensDashes - Whether to add dashes between the tens and ones. - * @returns string The name for the number. - */ -const makeHundredsName = (hundreds: number, tens: number, ones: number, addTensDashes: boolean) => { - if (hundreds === 0) { - return makeTensName(tens, ones, addTensDashes); - } - - if (tens === 0 && ones === 0) { - return `${ONES[hundreds]} ${HUNDRED}` as const; - } - - return `${ONES[hundreds]} ${HUNDRED} ${makeTensName(tens, ones, addTensDashes)}` as const; -}; - -/** - * Builds a name for numbers in the millions. - * @param millions - Millions digit. - * @param currentMillia - Current millia- group. - * @param longestMilliaCount - Number of millia- groups. - * @returns string The millions prefix. - */ -const makeMillionsPrefix = ( - millions: number, - currentMillia: GroupPlace, - longestMilliaCount: GroupPlace, -) => { - if (currentMillia === BigInt(0) && longestMilliaCount === BigInt(0)) { - return MILLIONS_SPECIAL_PREFIXES[millions] as MillionsSpecialPrefix; - } - - return MILLIONS_PREFIXES[millions] as MillionsPrefix; -}; - -/** - * Builds a name for numbers in the decillions. - * @param decillions - Decillions digit. - * @param millions - Millions digit. - * @param currentMillia - Current millia- group. - * @param longestMilliaCount - Number of millia- groups. - * @returns string The decillions prefix. - */ -const makeDecillionsPrefix = ( - decillions: number, - millions: number, - currentMillia: GroupPlace, - longestMilliaCount: GroupPlace, -) => { - if (decillions === 0) { - return makeMillionsPrefix(millions, currentMillia, longestMilliaCount); - } - - const onesPrefix = MILLIONS_PREFIXES[millions] as MillionsPrefix; - const tensName = DECILLIONS_PREFIXES[decillions] as DecillionsPrefix; - return `${onesPrefix}${tensName}` as const; -}; - -/** - * Builds a name for numbers in the centillions. - * @param centillions - Centillions digit. - * @param decillions - Decillions digit. - * @param millions - Millions digit. - * @param currentMillia - Current millia- group. - * @param longestMilliaCount - Number of millia- groups. - * @returns string The centillions prefix. - */ -const makeCentillionsPrefix = ( - centillions: number, - decillions: number, - millions: number, - currentMillia: GroupPlace, - longestMilliaCount: GroupPlace, -) => { - if (centillions === 0) { - return makeDecillionsPrefix(decillions, millions, currentMillia, longestMilliaCount); - } - - const onesPrefix = MILLIONS_PREFIXES[millions] as MillionsPrefix; - const tensName = DECILLIONS_PREFIXES[decillions] as DecillionsPrefix; - const hundredsName = CENTILLIONS_PREFIXES[centillions] as CentillionsPrefix; - return `${hundredsName}${onesPrefix}${decillions > 0 ? tensName : ''}` as const; -}; - -/** - * Repeats a string a given number of times. - * @param s - String to repeat. - * @param count - Number of times to repeat the string. - * @returns string The repeated string. - */ -const repeatString = (s: string, count: GroupPlace) => { - let result = ''; - for (let i = BigInt(0); i < count; i += BigInt(1)) { - result += s; - } - return result; -}; - const getGroupName = (place: GroupPlace, shortenMillia: boolean) => { if (place === BigInt(0)) { return '' as const; @@ -238,48 +103,6 @@ const getGroupName = (place: GroupPlace, shortenMillia: boolean) => { return `${groupGroups}${ILLION_SUFFIX}` as const; }; -export interface StringifyGroupsOptions { - /** - * Whether to add dashes between tens and ones (e.g. "sixty-nine"). - */ - addTensDashes?: boolean; - /** - * Use "millia^2-tillion" instead of "milliamilliatillion". - */ - shortenMillia?: boolean; -} - -/** - * Creates a group string. - * @param groups - The groups. - * @param options - Options to use when creating the group. - * @returns string[] The groups represented into strings. - */ -export const stringifyGroups = (groups: Group[], options?: StringifyGroupsOptions): string[] => { - const filteredGroups = groups.filter(([digits, place]) => ( - place === BigInt(0) || digits !== EMPTY_GROUP_DIGITS - )); - - return filteredGroups.map( - ([group, place]) => { - const makeHundredsArgs = group - .padStart(3, '0') - .split('') - .map((s) => Number(s)) as [number, number, number]; - - const groupDigitsName = makeHundredsName( - ...makeHundredsArgs, - options?.addTensDashes ?? true, - ); - const groupName = getGroupName(place, options?.shortenMillia ?? false); - if (groupName.length > 0) { - return `${groupDigitsName} ${groupName}`; - } - return groupDigitsName; - }, - ); -}; - /** * Group a number string into groups of three digits, starting from the decimal point. * @param value - The number string to group. @@ -306,7 +129,7 @@ export const splitIntoGroups = (value: string): Group[] => { if (lastGroup[GROUP_PLACE_INDEX] === currentPlace) { const lastGroupDigits = lastGroup[0].split(''); lastGroupDigits[currentPlaceInGroup] = c; - return [...acc.slice(0, -1), [ + return [...acc.slice(0, -1) ?? [], [ lastGroupDigits.join('') as GroupDigits, currentPlace, ]]; @@ -317,27 +140,40 @@ export const splitIntoGroups = (value: string): Group[] => { ); }; -export interface MergeTokensOptions { - oneGroupPerLine?: boolean; -} - /** - * Formats the final tokenized string. - * @param tokens - The tokens to finalize. - * @param options - The options to use. + * Creates a group string. + * @param groups - The groups. + * @param options - Options to use when creating the group. + * @returns string[] The groups represented into strings. */ -export const mergeTokens = (tokens: string[], options?: MergeTokensOptions) => ( - tokens - .map((t) => t.trim()) - .join(options?.oneGroupPerLine ? '\n' : GROUP_SEPARATOR) - .trim() -); +export const stringifyGroups = (groups: Group[], options?: StringifyGroupsOptions): string[] => { + const filteredGroups = groups.filter(([digits, place]) => ( + place === BigInt(0) || digits !== EMPTY_GROUP_DIGITS + )); -/** - * Makes a negative string. - * @param s - The string to make negative. - */ -export const makeNegative = (s: string) => { - const negativePrefix = `${NEGATIVE} `; - return s.startsWith(negativePrefix) ? s.slice(negativePrefix.length) : `${negativePrefix}${s}`; + return filteredGroups.map( + ([group, place]) => { + const makeHundredsArgs = group + .padStart(3, '0') + .split('') + .map((s) => Number(s)) as [number, number, number]; + + const groupDigitsName = makeHundredsName( + ...makeHundredsArgs, + options?.addTensDashes ?? true, + ); + const groupName = getGroupName(place, options?.shortenMillia ?? false); + if (groupName.length > 0) { + return `${groupDigitsName} ${groupName}`; + } + return groupDigitsName; + }, + ); }; + +export { + StringifyGroupsOptions, + MergeTokensOptions, + mergeTokens, + makeNegative, +} from '../../en/common'; diff --git a/packages/core/src/systems/en/common.ts b/packages/core/src/systems/en/common.ts index 4c3ef48..30fa4ab 100644 --- a/packages/core/src/systems/en/common.ts +++ b/packages/core/src/systems/en/common.ts @@ -1,4 +1,4 @@ -import { Group } from '../../common'; +import { Group, GroupPlace } from '../../common'; export const GROUP_SEPARATOR = ' ' as const; @@ -175,3 +175,169 @@ export const MILLIA_PREFIX = 'millia' as const; * Suffix for -illion number names. */ export const ILLION_SUFFIX = 'illion' as const; + +/** + * Builds a name for numbers in tens and ones. + * @param tens - Tens digit. + * @param ones - Ones digit. + * @param addTensDashes - Whether to add dashes between the tens and ones. + * @returns string The name for the number. + */ +const makeTensName = (tens: number, ones: number, addTensDashes: boolean) => { + if (tens === 0) { + return ONES[ones]; + } + + if (tens === 1) { + return TEN_PLUS_ONES[ones] as unknown as TenPlusOnesName; + } + + if (ones === 0) { + return TENS[tens]; + } + + return `${TENS[tens] as Exclude}${addTensDashes ? TENS_ONES_SEPARATOR : ' '}${ONES[ones] as Exclude}` as const; +}; + +/** + * Builds a name for numbers in hundreds, tens, and ones. + * @param hundreds - Hundreds digit. + * @param tens - Tens digit. + * @param ones - Ones digit. + * @param addTensDashes - Whether to add dashes between the tens and ones. + * @returns string The name for the number. + */ +export const makeHundredsName = ( + hundreds: number, + tens: number, + ones: number, + addTensDashes: boolean, +) => { + if (hundreds === 0) { + return makeTensName(tens, ones, addTensDashes); + } + + if (tens === 0 && ones === 0) { + return `${ONES[hundreds]} ${HUNDRED}` as const; + } + + return `${ONES[hundreds]} ${HUNDRED} ${makeTensName(tens, ones, addTensDashes)}` as const; +}; + +/** + * Builds a name for numbers in the millions. + * @param millions - Millions digit. + * @param currentMillia - Current millia- group. + * @param longestMilliaCount - Number of millia- groups. + * @returns string The millions prefix. + */ +const makeMillionsPrefix = ( + millions: number, + currentMillia: GroupPlace, + longestMilliaCount: GroupPlace, +) => { + if (currentMillia === BigInt(0) && longestMilliaCount === BigInt(0)) { + return MILLIONS_SPECIAL_PREFIXES[millions] as MillionsSpecialPrefix; + } + + return MILLIONS_PREFIXES[millions] as MillionsPrefix; +}; + +/** + * Builds a name for numbers in the decillions. + * @param decillions - Decillions digit. + * @param millions - Millions digit. + * @param currentMillia - Current millia- group. + * @param longestMilliaCount - Number of millia- groups. + * @returns string The decillions prefix. + */ +const makeDecillionsPrefix = ( + decillions: number, + millions: number, + currentMillia: GroupPlace, + longestMilliaCount: GroupPlace, +) => { + if (decillions === 0) { + return makeMillionsPrefix(millions, currentMillia, longestMilliaCount); + } + + const onesPrefix = MILLIONS_PREFIXES[millions] as MillionsPrefix; + const tensName = DECILLIONS_PREFIXES[decillions] as DecillionsPrefix; + return `${onesPrefix}${tensName}` as const; +}; + +/** + * Builds a name for numbers in the centillions. + * @param centillions - Centillions digit. + * @param decillions - Decillions digit. + * @param millions - Millions digit. + * @param currentMillia - Current millia- group. + * @param longestMilliaCount - Number of millia- groups. + * @returns string The centillions prefix. + */ +export const makeCentillionsPrefix = ( + centillions: number, + decillions: number, + millions: number, + currentMillia: GroupPlace, + longestMilliaCount: GroupPlace, +) => { + if (centillions === 0) { + return makeDecillionsPrefix(decillions, millions, currentMillia, longestMilliaCount); + } + + const onesPrefix = MILLIONS_PREFIXES[millions] as MillionsPrefix; + const tensName = DECILLIONS_PREFIXES[decillions] as DecillionsPrefix; + const hundredsName = CENTILLIONS_PREFIXES[centillions] as CentillionsPrefix; + return `${hundredsName}${onesPrefix}${decillions > 0 ? tensName : ''}` as const; +}; + +/** + * Repeats a string a given number of times. + * @param s - String to repeat. + * @param count - Number of times to repeat the string. + * @returns string The repeated string. + */ +export const repeatString = (s: string, count: GroupPlace) => { + let result = ''; + for (let i = BigInt(0); i < count; i += BigInt(1)) { + result += s; + } + return result; +}; + +export interface StringifyGroupsOptions { + /** + * Whether to add dashes between tens and ones (e.g. "sixty-nine"). + */ + addTensDashes?: boolean; + /** + * Use "millia^2-tillion" instead of "milliamilliatillion". + */ + shortenMillia?: boolean; +} + +export interface MergeTokensOptions { + oneGroupPerLine?: boolean; +} + +/** + * Formats the final tokenized string. + * @param tokens - The tokens to finalize. + * @param options - The options to use. + */ +export const mergeTokens = (tokens: string[], options?: MergeTokensOptions) => ( + tokens + .map((t) => t.trim()) + .join(options?.oneGroupPerLine ? '\n' : GROUP_SEPARATOR) + .trim() +); + +/** + * Makes a negative string. + * @param s - The string to make negative. + */ +export const makeNegative = (s: string) => { + const negativePrefix = `${NEGATIVE} `; + return s.startsWith(negativePrefix) ? s.slice(negativePrefix.length) : `${negativePrefix}${s}`; +};