@@ -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<TensName, 'zero' | 'ten'>}${addTensDashes ? TENS_ONES_SEPARATOR : ' '}${ONES[ones] as Exclude<OnesName, 'zero'>}` 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'; |
@@ -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<TensName, 'zero' | 'ten'>}${addTensDashes ? TENS_ONES_SEPARATOR : ' '}${ONES[ones] as Exclude<OnesName, 'zero'>}` 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'; |
@@ -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<TensName, 'zero' | 'ten'>}${addTensDashes ? TENS_ONES_SEPARATOR : ' '}${ONES[ones] as Exclude<OnesName, 'zero'>}` 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}`; | |||
}; |