|
@@ -132,7 +132,7 @@ const makeTensName = (tens: number, ones: number) => { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (tens === 1) { |
|
|
if (tens === 1) { |
|
|
return TEN_PLUS_ONES[ones] as TenPlusOnesName; |
|
|
|
|
|
|
|
|
return TEN_PLUS_ONES[ones] as unknown as TenPlusOnesName; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (ones === 0) { |
|
|
if (ones === 0) { |
|
@@ -172,7 +172,12 @@ const makeDecillionsPrefix = (decillions: number, millions: number, milliaCount: |
|
|
return `${onesPrefix}${tensName}` as const; |
|
|
return `${onesPrefix}${tensName}` as const; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const makeCentillionsPrefix = (centillions: number, decillions: number, millions: number, milliaCount: number) => { |
|
|
|
|
|
|
|
|
const makeCentillionsPrefix = ( |
|
|
|
|
|
centillions: number, |
|
|
|
|
|
decillions: number, |
|
|
|
|
|
millions: number, |
|
|
|
|
|
milliaCount: number, |
|
|
|
|
|
) => { |
|
|
if (centillions === 0) { |
|
|
if (centillions === 0) { |
|
|
return makeDecillionsPrefix(decillions, millions, milliaCount); |
|
|
return makeDecillionsPrefix(decillions, millions, milliaCount); |
|
|
} |
|
|
} |
|
@@ -210,10 +215,10 @@ const getGroupName = (place: number, shortenMillia: boolean) => { |
|
|
|
|
|
|
|
|
return [ |
|
|
return [ |
|
|
[c + firstGroup[0], currentPlace], |
|
|
[c + firstGroup[0], currentPlace], |
|
|
...acc.slice(1) |
|
|
|
|
|
|
|
|
...acc.slice(1), |
|
|
]; |
|
|
]; |
|
|
}, |
|
|
}, |
|
|
[] |
|
|
|
|
|
|
|
|
[], |
|
|
) |
|
|
) |
|
|
.map(([group, groupPlace]) => [group.padStart(3, '0'), groupPlace] as const) |
|
|
.map(([group, groupPlace]) => [group.padStart(3, '0'), groupPlace] as const) |
|
|
.filter(([group]) => group !== '000') |
|
|
.filter(([group]) => group !== '000') |
|
@@ -248,7 +253,11 @@ const getGroupName = (place: number, shortenMillia: boolean) => { |
|
|
return `${groupGroups}${ILLION_SUFFIX}` as const; |
|
|
return `${groupGroups}${ILLION_SUFFIX}` as const; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
export const makeGroup = (group: string, place: number, options?: Record<string, unknown>): string => { |
|
|
|
|
|
|
|
|
export const makeGroup = ( |
|
|
|
|
|
group: string, |
|
|
|
|
|
place: number, |
|
|
|
|
|
options?: Record<string, unknown>, |
|
|
|
|
|
): string => { |
|
|
const makeHundredsArgs = group |
|
|
const makeHundredsArgs = group |
|
|
.padStart(3, '0') |
|
|
.padStart(3, '0') |
|
|
.split('') |
|
|
.split('') |
|
@@ -274,7 +283,8 @@ export const group = (value: string): Group[] => { |
|
|
decimalPoint: DECIMAL_POINT, |
|
|
decimalPoint: DECIMAL_POINT, |
|
|
groupingSymbol: GROUPING_SYMBOL, |
|
|
groupingSymbol: GROUPING_SYMBOL, |
|
|
exponentDelimiter, |
|
|
exponentDelimiter, |
|
|
}) |
|
|
|
|
|
|
|
|
}, |
|
|
|
|
|
) |
|
|
.split(exponentDelimiter); |
|
|
.split(exponentDelimiter); |
|
|
const exponent = Number(exponentString); |
|
|
const exponent = Number(exponentString); |
|
|
const significantDigits = significand.replace(DECIMAL_POINT, ''); |
|
|
const significantDigits = significand.replace(DECIMAL_POINT, ''); |
|
@@ -288,7 +298,7 @@ export const group = (value: string): Group[] => { |
|
|
lastGroupDigits[currentPlaceInGroup] = c; |
|
|
lastGroupDigits[currentPlaceInGroup] = c; |
|
|
return [...acc.slice(0, -1) ?? [], [ |
|
|
return [...acc.slice(0, -1) ?? [], [ |
|
|
lastGroupDigits.join(''), |
|
|
lastGroupDigits.join(''), |
|
|
currentPlace |
|
|
|
|
|
|
|
|
currentPlace, |
|
|
]]; |
|
|
]]; |
|
|
} |
|
|
} |
|
|
return [...acc, [c.padEnd(3, '0'), currentPlace]]; |
|
|
return [...acc, [c.padEnd(3, '0'), currentPlace]]; |
|
@@ -316,8 +326,8 @@ export const makeNegative = (s: string) => ( |
|
|
`${NEGATIVE} ${s}` |
|
|
`${NEGATIVE} ${s}` |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
export const tokenize = (s: string) => ( |
|
|
|
|
|
s.split(' ').filter((s) => s.length > 0) |
|
|
|
|
|
|
|
|
export const tokenize = (stringValue: string) => ( |
|
|
|
|
|
stringValue.split(' ').filter((maybeToken) => maybeToken.length > 0) |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
const FINAL_TOKEN = ''; |
|
|
const FINAL_TOKEN = ''; |
|
@@ -328,9 +338,7 @@ const getGroupFromGroupName = (groupName: string) => { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const groupNameBase = groupName.replace(ILLION_SUFFIX, ''); |
|
|
const groupNameBase = groupName.replace(ILLION_SUFFIX, ''); |
|
|
const specialMillions = MILLIONS_SPECIAL_PREFIXES.findIndex((p) => { |
|
|
|
|
|
return groupNameBase === p; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
const specialMillions = MILLIONS_SPECIAL_PREFIXES.findIndex((p) => groupNameBase === p); |
|
|
|
|
|
|
|
|
if (specialMillions > -1) { |
|
|
if (specialMillions > -1) { |
|
|
return 1 + specialMillions; |
|
|
return 1 + specialMillions; |
|
@@ -338,7 +346,7 @@ const getGroupFromGroupName = (groupName: string) => { |
|
|
|
|
|
|
|
|
let groupNameCurrent = groupNameBase; |
|
|
let groupNameCurrent = groupNameBase; |
|
|
|
|
|
|
|
|
let millias = [0]; |
|
|
|
|
|
|
|
|
const millias = [0]; |
|
|
let milliaIndex = 0; |
|
|
let milliaIndex = 0; |
|
|
|
|
|
|
|
|
while (groupNameCurrent.length > 0) { |
|
|
while (groupNameCurrent.length > 0) { |
|
@@ -346,9 +354,9 @@ const getGroupFromGroupName = (groupName: string) => { |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const centillions = CENTILLIONS_PREFIXES.findIndex((p) => { |
|
|
|
|
|
return p.length > 0 && groupNameCurrent.startsWith(p); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
const centillions = CENTILLIONS_PREFIXES.findIndex((p) => ( |
|
|
|
|
|
p.length > 0 && groupNameCurrent.startsWith(p) |
|
|
|
|
|
)); |
|
|
|
|
|
|
|
|
if (centillions > -1) { |
|
|
if (centillions > -1) { |
|
|
milliaIndex = 0; |
|
|
milliaIndex = 0; |
|
@@ -357,9 +365,9 @@ const getGroupFromGroupName = (groupName: string) => { |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const decillions = DECILLIONS_PREFIXES.findIndex((p) => { |
|
|
|
|
|
return p.length > 0 && groupNameCurrent.startsWith(p); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
const decillions = DECILLIONS_PREFIXES.findIndex((p) => ( |
|
|
|
|
|
p.length > 0 && groupNameCurrent.startsWith(p) |
|
|
|
|
|
)); |
|
|
|
|
|
|
|
|
if (decillions > -1) { |
|
|
if (decillions > -1) { |
|
|
milliaIndex = 0; |
|
|
milliaIndex = 0; |
|
@@ -368,9 +376,9 @@ const getGroupFromGroupName = (groupName: string) => { |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const millions = MILLIONS_PREFIXES.findIndex((p) => { |
|
|
|
|
|
return p.length > 0 && groupNameCurrent.startsWith(p); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
const millions = MILLIONS_PREFIXES.findIndex((p) => ( |
|
|
|
|
|
p.length > 0 && groupNameCurrent.startsWith(p) |
|
|
|
|
|
)); |
|
|
|
|
|
|
|
|
if (millions > -1) { |
|
|
if (millions > -1) { |
|
|
milliaIndex = 0; |
|
|
milliaIndex = 0; |
|
@@ -407,7 +415,7 @@ const getGroupFromGroupName = (groupName: string) => { |
|
|
millias |
|
|
millias |
|
|
.map((s) => s.toString().padStart(3, '0')) |
|
|
.map((s) => s.toString().padStart(3, '0')) |
|
|
.reverse() |
|
|
.reverse() |
|
|
.join('') |
|
|
|
|
|
|
|
|
.join(''), |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
return 1 + bigGroupPlace; |
|
|
return 1 + bigGroupPlace; |
|
@@ -415,11 +423,11 @@ const getGroupFromGroupName = (groupName: string) => { |
|
|
|
|
|
|
|
|
enum ParseGroupsMode { |
|
|
enum ParseGroupsMode { |
|
|
INITIAL = 'unknown', |
|
|
INITIAL = 'unknown', |
|
|
ONES = 'ones', |
|
|
|
|
|
TENS = 'tens', |
|
|
|
|
|
TEN_PLUS_ONES = 'tenPlusOnes', |
|
|
|
|
|
HUNDRED = 'hundred', |
|
|
|
|
|
THOUSAND = 'thousand', |
|
|
|
|
|
|
|
|
ONES_MODE = 'ones', |
|
|
|
|
|
TENS_MODE = 'tens', |
|
|
|
|
|
TEN_PLUS_ONES_MODE = 'tenPlusOnes', |
|
|
|
|
|
HUNDRED_MODE = 'hundred', |
|
|
|
|
|
THOUSAND_MODE = 'thousand', |
|
|
DONE = 'done', |
|
|
DONE = 'done', |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -435,7 +443,7 @@ export const parseGroups = (tokens: string[]) => { |
|
|
const lastGroup = acc.groups.at(-1) ?? ['000', 0]; |
|
|
const lastGroup = acc.groups.at(-1) ?? ['000', 0]; |
|
|
|
|
|
|
|
|
if (token === THOUSAND || token.endsWith(ILLION_SUFFIX)) { |
|
|
if (token === THOUSAND || token.endsWith(ILLION_SUFFIX)) { |
|
|
if (acc.mode === ParseGroupsMode.ONES) { |
|
|
|
|
|
|
|
|
if (acc.mode === ParseGroupsMode.ONES_MODE) { |
|
|
const ones = ONES.findIndex((o) => o === acc.lastToken); |
|
|
const ones = ONES.findIndex((o) => o === acc.lastToken); |
|
|
lastGroup[0] = `${lastGroup[0].slice(0, 2)}${ones}`; |
|
|
lastGroup[0] = `${lastGroup[0].slice(0, 2)}${ones}`; |
|
|
} |
|
|
} |
|
@@ -446,24 +454,24 @@ export const parseGroups = (tokens: string[]) => { |
|
|
...acc, |
|
|
...acc, |
|
|
groups: [...acc.groups.slice(0, -1), lastGroup], |
|
|
groups: [...acc.groups.slice(0, -1), lastGroup], |
|
|
lastToken: token, |
|
|
lastToken: token, |
|
|
mode: ParseGroupsMode.THOUSAND, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
mode: ParseGroupsMode.THOUSAND_MODE, |
|
|
|
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (token === HUNDRED) { |
|
|
if (token === HUNDRED) { |
|
|
if (acc.mode === ParseGroupsMode.ONES) { |
|
|
|
|
|
|
|
|
if (acc.mode === ParseGroupsMode.ONES_MODE) { |
|
|
const hundreds = ONES.findIndex((o) => o === acc.lastToken); |
|
|
const hundreds = ONES.findIndex((o) => o === acc.lastToken); |
|
|
lastGroup[0] = `${hundreds}${lastGroup[0].slice(1)}`; |
|
|
lastGroup[0] = `${hundreds}${lastGroup[0].slice(1)}`; |
|
|
return { |
|
|
return { |
|
|
...acc, |
|
|
...acc, |
|
|
groups: [...acc.groups.slice(0, -1), lastGroup], |
|
|
groups: [...acc.groups.slice(0, -1), lastGroup], |
|
|
mode: ParseGroupsMode.HUNDRED, |
|
|
|
|
|
|
|
|
mode: ParseGroupsMode.HUNDRED_MODE, |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (token === FINAL_TOKEN) { |
|
|
if (token === FINAL_TOKEN) { |
|
|
if (acc.mode === ParseGroupsMode.ONES) { |
|
|
|
|
|
|
|
|
if (acc.mode === ParseGroupsMode.ONES_MODE) { |
|
|
const ones = ONES.findIndex((o) => o === acc.lastToken); |
|
|
const ones = ONES.findIndex((o) => o === acc.lastToken); |
|
|
lastGroup[0] = `${lastGroup[0].slice(0, 2)}${ones}`; |
|
|
lastGroup[0] = `${lastGroup[0].slice(0, 2)}${ones}`; |
|
|
lastGroup[1] = 0; |
|
|
lastGroup[1] = 0; |
|
@@ -476,19 +484,19 @@ export const parseGroups = (tokens: string[]) => { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (ONES.includes(token as OnesName)) { |
|
|
if (ONES.includes(token as OnesName)) { |
|
|
if (acc.mode === ParseGroupsMode.THOUSAND) { |
|
|
|
|
|
|
|
|
if (acc.mode === ParseGroupsMode.THOUSAND_MODE) { |
|
|
return { |
|
|
return { |
|
|
...acc, |
|
|
...acc, |
|
|
lastToken: token, |
|
|
lastToken: token, |
|
|
mode: ParseGroupsMode.ONES, |
|
|
|
|
|
|
|
|
mode: ParseGroupsMode.ONES_MODE, |
|
|
groups: [...acc.groups, ['000', 0]], |
|
|
groups: [...acc.groups, ['000', 0]], |
|
|
} |
|
|
|
|
|
|
|
|
}; |
|
|
} |
|
|
} |
|
|
return { |
|
|
return { |
|
|
...acc, |
|
|
...acc, |
|
|
lastToken: token, |
|
|
lastToken: token, |
|
|
mode: ParseGroupsMode.ONES, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
mode: ParseGroupsMode.ONES_MODE, |
|
|
|
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const tenPlusOnes = TEN_PLUS_ONES.findIndex((t) => t === token); |
|
|
const tenPlusOnes = TEN_PLUS_ONES.findIndex((t) => t === token); |
|
@@ -497,8 +505,8 @@ export const parseGroups = (tokens: string[]) => { |
|
|
return { |
|
|
return { |
|
|
...acc, |
|
|
...acc, |
|
|
lastToken: token, |
|
|
lastToken: token, |
|
|
mode: ParseGroupsMode.TEN_PLUS_ONES, |
|
|
|
|
|
groups: [...acc.groups.slice(0, -1), lastGroup] |
|
|
|
|
|
|
|
|
mode: ParseGroupsMode.TEN_PLUS_ONES_MODE, |
|
|
|
|
|
groups: [...acc.groups.slice(0, -1), lastGroup], |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@@ -508,7 +516,7 @@ export const parseGroups = (tokens: string[]) => { |
|
|
return { |
|
|
return { |
|
|
...acc, |
|
|
...acc, |
|
|
lastToken: token, |
|
|
lastToken: token, |
|
|
mode: ParseGroupsMode.TENS, |
|
|
|
|
|
|
|
|
mode: ParseGroupsMode.TENS_MODE, |
|
|
groups: [...acc.groups.slice(0, -1), lastGroup], |
|
|
groups: [...acc.groups.slice(0, -1), lastGroup], |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
@@ -533,11 +541,11 @@ export const combineGroups = (groups: Group[]) => { |
|
|
const firstGroup = groupsSorted[0]; |
|
|
const firstGroup = groupsSorted[0]; |
|
|
const firstGroupPlace = firstGroup[1]; |
|
|
const firstGroupPlace = firstGroup[1]; |
|
|
const digits = groupsSorted.reduce( |
|
|
const digits = groupsSorted.reduce( |
|
|
(s, group) => { |
|
|
|
|
|
const [groupDigits] = group; |
|
|
|
|
|
return `${s}${groupDigits}`; |
|
|
|
|
|
|
|
|
(previousDigits, thisGroup) => { |
|
|
|
|
|
const [groupDigits] = thisGroup; |
|
|
|
|
|
return `${previousDigits}${groupDigits}`; |
|
|
}, |
|
|
}, |
|
|
'' |
|
|
|
|
|
|
|
|
'', |
|
|
).replace(/^0+/, '') || '0'; |
|
|
).replace(/^0+/, '') || '0'; |
|
|
const firstGroupDigits = firstGroup[0]; |
|
|
const firstGroupDigits = firstGroup[0]; |
|
|
const firstGroupDigitsWithoutZeroes = firstGroupDigits.replace(/^0+/, ''); |
|
|
const firstGroupDigitsWithoutZeroes = firstGroupDigits.replace(/^0+/, ''); |
|
|