Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save DavidWesley/156e454c33863d5f972147121c50958c to your computer and use it in GitHub Desktop.
Save DavidWesley/156e454c33863d5f972147121c50958c to your computer and use it in GitHub Desktop.
Conversor de número inteiro para número por extenso (string) em português escrito em Javascript
export const convertNumberToPortugueseNomenclature = function PortugueseNumeralNomenclatureConverter() {
const PORTUGUESE_UNITS_NAMES_LIST = [
"",
"um",
"dois",
"tres",
"quatro",
"cinco",
"seis",
"sete",
"oito",
"nove",
"dez",
"onze",
"doze",
"treze",
"quatorze",
"quinze",
"dezesseis",
"dezessete",
"dezoito",
"dezenove",
];
const PORTUGUESE_DOZENS_NAMES_LIST = [
"",
"dez",
"vinte",
"trinta",
"quarenta",
"cinquenta",
"sessenta",
"setenta",
"oitenta",
"noventa",
"cem",
];
const PORTUGUESE_HUNDREDS_NAMES_LIST = [
"",
"cento",
"duzentos",
"trezentos",
"quatrocentos",
"quinhentos",
"seiscentos",
"setecentos",
"oitocentos",
"novecentos",
];
const PORTUGUESE_GROUPS_ENUM = Object.values({
get simple() { return { plural: "", single: "" } },
get thousand() { return { plural: "mil", single: "mil" } },
get million() { return { plural: "milhões", single: "milhão" } },
get billion() { return { plural: "bilhões", single: "bilhão" } },
get trillion() { return { plural: "trilhões", single: "trilhão" } },
get quadrillion() { return { plural: "quatrilhões", single: "quatrilhão" } },
get quintillion() { return { plural: "quintilhões", single: "quintilhão" } },
get sextillion() { return { plural: "sextilhões", single: "sextilhão" } },
get septillion() { return { plural: "septilhões", single: "septilhão" } },
get octillion() { return { plural: "octilhões", single: "octilhão" } },
get nonillion() { return { plural: "nonilhões", single: "nonilhão" } },
get decillion() { return { plural: "decilhões", single: "decilhão" } },
// And so on...
});
const PORTUGUESE_DEFAULT_AGGREGATOR_WORD = "e";
const MINIMUM_INTEGER_DIGITS = 9;
const MAXIMUM_FRACTION_DIGITS = 0;
const NUMBER_FORMATTER = new Intl.NumberFormat("pt-BR", {
style: "decimal",
useGrouping: true,
minimumIntegerDigits: MINIMUM_INTEGER_DIGITS,
maximumFractionDigits: MAXIMUM_FRACTION_DIGITS,
});
const PortugueseUnitsNamesMap = new Map(Object.entries(PORTUGUESE_UNITS_NAMES_LIST));
const PortugueseDozensNamesMap = new Map(Object.entries(PORTUGUESE_DOZENS_NAMES_LIST));
const PortugueseHundredsNamesMap = new Map(Object.entries(PORTUGUESE_HUNDREDS_NAMES_LIST));
/**
* @param {string | number | bigint} value
* @param {Intl.NumberFormatPartTypes} groupName
*/
function extractGroupsFromNumber(value, groupName) {
return NUMBER_FORMATTER
.formatToParts(value)
.reduce((groups, { type, value }) => {
if (type === groupName) groups.push(value);
return groups;
}, []);
}
/**
* @param {string} orders
* @param {string} joiner
* @param {{ single: string, plural: string }} groupOptions
*/
function toNomenclature(
orders = "000",
joiner = PORTUGUESE_DEFAULT_AGGREGATOR_WORD,
groupOptions = PORTUGUESE_GROUPS_ENUM[0]
) {
orders = orders.padStart(3, "0");
const num = Number.parseInt(orders, 10);
const unit = num >= 2 ? groupOptions.plural : groupOptions.single;
if (num === 0) { return "" }
else if (num === 100) { return String.prototype.concat(joiner, " ", PortugueseDozensNamesMap.get("10"), " ", unit) }
else if (num % 100 === 0) { return String.prototype.concat(joiner, " ", PortugueseHundredsNamesMap.get(orders[0]), " ", unit) }
else {
return orders
.split("", 3)
.map((digit, index, arr) => {
switch (index) {
case 0: return PortugueseHundredsNamesMap.get(digit).concat(digit !== "0" ? " " : "", joiner);
case 1: return ["0", "1"].includes(digit) ? "" : PortugueseDozensNamesMap.get(digit);
case 2: {
if (arr[index - 1] === "1") return PortugueseUnitsNamesMap.get("1".concat(digit));
else if (digit === "0" || arr[index - 1] === "0") return PortugueseUnitsNamesMap.get(digit);
else return String.prototype.concat(joiner, " ", PortugueseUnitsNamesMap.get(digit));
}
}
})
.filter(value => Boolean(value))
.join(" ")
.concat(" ", unit);
}
}
function converter(value = "") {
if (value == 0) return "zero";
return extractGroupsFromNumber(value, "integer")
.map((orders, index, arr) => toNomenclature(orders, PORTUGUESE_DEFAULT_AGGREGATOR_WORD, PORTUGUESE_GROUPS_ENUM[arr.length - index - 1]))
.join(" ")
.trim()
.replace(RegExp(`^${PORTUGUESE_DEFAULT_AGGREGATOR_WORD}\\s+`), "")
.replace(/(^um mil\b)/, "mil");
}
return Object.freeze({ convert: converter.bind(PortugueseNumeralNomenclatureConverter) });
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment