numberify-text
Version:
A library to convert text numbers to their numeric equivalents.
180 lines (179 loc) • 6.76 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.numberifyString_EN = void 0;
// Dictionary for numbers from 0 to 100, which are straightforward to represent.
const simpleNumDict = {
"zero": 0, "one": 1, "two": 2, "three": 3, "four": 4,
"five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9,
"ten": 10, "eleven": 11, "twelve": 12, "thirteen": 13, "fourteen": 14,
"fifteen": 15, "sixteen": 16, "seventeen": 17, "eighteen": 18, "nineteen": 19,
"twenty": 20, "thirty": 30, "forty": 40,
"fifty": 50, "sixty": 60, "seventy": 70, "eighty": 80,
"ninety": 90
};
// Dictionary for multipliers like "thousand", "million", etc., including "hundred".
const multiplierNumDict = {
"hundred": 100, "hundreds": 100, "thousand": 1000, "thousands": 1000, "million": 1000000,
"millions": 1000000, "billion": 1000000000, "billions": 1000000000, "trillion": 1000000000000,
"trillions": 1000000000000
};
// Normalizes a string by removing diacritics.
function normalizeString(str) {
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
}
// Handles hyphenated numbers like "thirty-two" and converts them to "thirty two".
function handleHyphenatedNumbers(words) {
return words.reduce((acc, word) => {
if (word.match(/([a-zA-Z])-([a-zA-Z])/)) {
return [...acc, ...word.split('-')];
}
else {
return [...acc, word];
}
}, []);
}
// Processes an array of words and converts words that represent numbers to their numeric form.
function processWordsToNumbers(words) {
let output = [];
for (let word of words) {
let normalizedWord = normalizeString(word);
if (simpleNumDict[normalizedWord]) {
output.push(simpleNumDict[normalizedWord].toString());
}
else {
output.push(word);
}
}
return output;
}
// Replaces "a" or "an" with "1" if the following word is a multiplier.
function replaceAorAnWithOneBeforeMultipliers(output) {
for (let i = 0; i < output.length - 1; i++) {
if (normalizeString(output[i]) === "a" || normalizeString(output[i]) === "an") {
if (multiplierNumDict[normalizeString(output[i + 1])]) {
output[i] = "1";
}
}
}
return output;
}
// Applies the multipliers to the numbers and sums them.
function applyMultipliersAndSum(output) {
const newOutput = [];
let segmentSum = 0;
let segmentLastSum = 0;
let segmentLastMultiplier = 0;
let fullSum = 0;
for (let i = 0; i < output.length; i++) {
let word = output[i];
let normalizedWord = normalizeString(word);
if (!isNaN(Number(word))) {
segmentSum += Number(word);
}
else {
if (multiplierNumDict[normalizedWord]) {
if (segmentSum === 0 && segmentLastSum === 0) {
segmentLastSum = 1 * multiplierNumDict[normalizedWord];
segmentLastMultiplier = multiplierNumDict[normalizedWord];
}
else if (segmentSum !== 0 && segmentLastSum === 0) {
segmentLastSum = segmentSum * multiplierNumDict[normalizedWord];
segmentLastMultiplier = multiplierNumDict[normalizedWord];
segmentSum = 0;
}
else if (segmentLastSum !== 0) {
if (multiplierNumDict[normalizedWord] < segmentLastMultiplier) {
fullSum += segmentLastSum;
segmentLastSum = segmentSum * multiplierNumDict[normalizedWord];
segmentSum = 0;
segmentLastMultiplier = multiplierNumDict[normalizedWord];
}
else if (multiplierNumDict[normalizedWord] > segmentLastMultiplier) {
segmentLastSum = (segmentSum + segmentLastSum) * multiplierNumDict[normalizedWord];
fullSum += segmentLastSum;
segmentSum = 0;
segmentLastSum = 0;
segmentLastMultiplier = 0;
}
}
}
else {
if (fullSum !== 0 || segmentLastSum !== 0 || segmentSum !== 0) {
fullSum += (segmentSum + segmentLastSum);
newOutput.push(fullSum.toString());
segmentSum = 0;
segmentLastSum = 0;
segmentLastMultiplier = 0;
fullSum = 0;
}
newOutput.push(word);
}
}
}
if (fullSum !== 0 || segmentLastSum !== 0 || segmentSum !== 0) {
fullSum += (segmentSum + segmentLastSum);
newOutput.push(fullSum.toString());
}
return newOutput;
}
// Sums the numbers that are found between words.
function sumNumbersBetweenWords(output) {
let finalOutput = [];
let tempSum = 0;
for (let word of output) {
if (!isNaN(Number(word))) {
tempSum += Number(word);
}
else {
if (tempSum > 0) {
finalOutput.push(tempSum.toString());
tempSum = 0;
}
finalOutput.push(word);
}
}
if (tempSum > 0) {
finalOutput.push(tempSum.toString());
}
return finalOutput;
}
// Handles decimal numbers in the string, replacing "point" with "."
function handleDecimalNumbers(output) {
let newOutput = [];
let appendDecimal = false;
for (let i = 0; i < output.length; i++) {
const word = output[i];
if (appendDecimal) {
if (!isNaN(Number(word))) {
newOutput[newOutput.length - 1] += "." + word;
appendDecimal = false;
}
else {
newOutput.push(".");
newOutput.push(word);
appendDecimal = false;
}
}
else {
if (normalizeString(word) === "point") {
appendDecimal = true;
}
else {
newOutput.push(word);
}
}
}
return newOutput;
}
// Main function that takes a sentence and "numberizes" it.
function numberifyString_EN(sentence) {
const words = sentence.split(' ');
let output = handleHyphenatedNumbers(words);
output = processWordsToNumbers(output);
output = replaceAorAnWithOneBeforeMultipliers(output);
output = applyMultipliersAndSum(output);
output = sumNumbersBetweenWords(output);
output = handleDecimalNumbers(output);
return output.join(' ').trim();
}
exports.numberifyString_EN = numberifyString_EN;