Created
July 9, 2020 15:06
-
-
Save Chrispassold/4151ed74132d25e6e4ec946e3193c97c to your computer and use it in GitHub Desktop.
Brazilian number converter to string
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.math.BigDecimal | |
import java.security.InvalidParameterException | |
import kotlin.text.StringBuilder | |
object BrazilianNumberStringConverter { | |
private val units = arrayOf( | |
"", | |
"um", | |
"dois", | |
"três", | |
"quatro", | |
"cinco", | |
"seis", | |
"sete", | |
"oito", | |
"nove", | |
"dez", | |
"onze", | |
"doze", | |
"treze", | |
"quatorze", | |
"quinze", | |
"dezesseis", | |
"dezessete", | |
"dezoito", | |
"dezenove" | |
) | |
private val dozens = arrayOf( | |
"", | |
"", | |
"vinte", | |
"trinta", | |
"quarenta", | |
"cinquenta", | |
"sessenta", | |
"setenta", | |
"oitenta", | |
"noventa" | |
) | |
private val hundreds = arrayOf( | |
"cem", | |
"cento", | |
"duzentos", | |
"trezentos", | |
"quatrocentos", | |
"quinhentos", | |
"seiscentos", | |
"setecentos", | |
"oitocentos", | |
"novecentos" | |
) | |
private fun BigDecimal.minus(double: Double) = this.minus(BigDecimal.valueOf(double)) | |
private fun BigDecimal.divideAndGetIntegerPart(double: Double) = | |
this.divide(BigDecimal.valueOf(double)).toBigInteger().toInt() | |
private data class NumberMap( | |
var millions: Int = 0, | |
var thousands: Int = 0, | |
var hundreds: Int = 0 | |
) { | |
private fun millions() = millions * 1000000 | |
private fun thousands() = thousands * 1000 | |
private fun hundreds() = hundreds | |
fun asInt(): Int { | |
return millions() + thousands() + hundreds() | |
} | |
override fun toString(): String { | |
return "Number(millions=$millions, thousands=$thousands, hundreds=$hundreds)" | |
} | |
} | |
private fun assertMaximmumValue(number: Int) { | |
if (number.toString().length > 9) | |
throw InvalidParameterException("Maximmum number is 999 millions") | |
} | |
private fun mapNumber(number: Int): NumberMap { | |
var value = number | |
val result = NumberMap() | |
// verifica quantos milhoes tem | |
result.millions = value / 1000000 | |
value = value.minus(result.millions * 1000000) | |
// verifica quantos milhares tem | |
result.thousands = value / 1000 | |
value = value.minus(result.thousands * 1000) | |
// verifica quantas centenas tem | |
result.hundreds = value | |
return result | |
} | |
private fun mapNumber(number: BigDecimal): NumberMap { | |
var value: BigDecimal = number.setScale(2, BigDecimal.ROUND_HALF_EVEN) | |
val result = NumberMap() | |
if (number <= BigDecimal.ZERO) | |
return result | |
// verifica quantos milhoes tem | |
result.millions = value.divideAndGetIntegerPart(1000000.0) | |
value = value.minus(result.millions * 1000000.0) | |
// verifica quantos milhares tem | |
result.thousands = value.divideAndGetIntegerPart(1000.0) | |
value = value.minus(result.thousands * 1000.0) | |
// verifica quantas centenas tem | |
result.hundreds = value.divideAndGetIntegerPart(1.0) | |
return result | |
} | |
private fun mapDecimalNumber(number: BigDecimal): NumberMap { | |
val decimals = number.remainder(BigDecimal.ONE).multiply(BigDecimal.valueOf(100.0)) | |
return mapNumber(decimals) | |
} | |
private fun formatDozenPart(number: Int): String { | |
val sb = StringBuilder() | |
if (number < 20) { | |
sb.append(units[number]) | |
} else { | |
val dozenPart = number / 10 | |
val unitPart = number % 10 | |
sb.append(dozens[dozenPart]) | |
if (unitPart > 0) | |
sb.append(" e ").append(units[unitPart]) | |
} | |
return sb.toString() | |
} | |
private fun formatHundredPart(number: Int): String { | |
val sb = StringBuilder() | |
if (number == 100) | |
return hundreds[0] | |
val hundredPart = number / 100 | |
val dozenPart = number % 100 | |
if (hundredPart > 0) | |
sb.append(hundreds[hundredPart]).append(if (dozenPart > 0) " e " else "") | |
if (dozenPart > 0) | |
sb.append(formatDozenPart(dozenPart)) | |
return sb.toString() | |
} | |
private fun formatQualifier(number: Int): String { | |
val sb = StringBuilder() | |
assertMaximmumValue(number) | |
val numberString = number.toString() | |
val numberObject = mapNumber(number) | |
when { | |
numberString.length > 6 -> { | |
// millions | |
sb.append(getStringNumber(numberObject.millions)) | |
.append(if (numberObject.millions > 1) " milhões " else " milhão ") | |
sb.append(getStringNumber(numberObject.thousands)).append(" mil ") | |
sb.append(getStringNumber(numberObject.hundreds)) | |
} | |
numberString.length > 3 -> { | |
// thousands | |
sb.append(getStringNumber(numberObject.thousands)).append(" mil ") | |
sb.append(getStringNumber(numberObject.hundreds)) | |
} | |
else -> { | |
// hundreds | |
sb.append(formatHundredPart(numberObject.hundreds)) | |
} | |
} | |
return sb.toString() | |
} | |
private fun getStringNumber(number: Int): String { | |
return formatQualifier(number) | |
} | |
fun convertToString(number: Int): String { | |
if (number < 0) return "0" | |
return getStringNumber(number) | |
} | |
fun convertToStringCurrency(number: BigDecimal): String { | |
val numbers = mapNumber(number) | |
val decimals = mapDecimalNumber(number) | |
val sb = StringBuilder() | |
val money = getStringNumber(numbers.asInt()) | |
val cents = getStringNumber(decimals.asInt()) | |
if (money.isNotBlank()) | |
sb.append(money).append(" reais") | |
if (cents.isNotBlank()) { | |
if (sb.isNotBlank()) | |
sb.append(" e ") | |
sb.append(cents).append(if (cents == units[1]) " centavo" else " centavos") | |
} | |
return sb.toString() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment