// Package say says numbers in English.
package say
import (
"math"
"strings"
)
// names for powers of thousand
var thousandName = []string{
"", " thousand", " million", " billion", " trillion",
}
// basic names, some could be concatenated, but does not worth the fuss
var tilTwenty = []string{
"zero", "one", "two", "three", "four",
"five", "six", "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen",
}
// names of tenth values
var tens = []string{
"XXX", // placeholder
"XXX", // placeholder
"twenty", "thirty", "forty", "fifty",
"sixty", "seventy", "eighty", "ninety",
}
func Say(input int64) (string, bool) {
if input > 999_999_999_999 || input < 0 {
return "", false
}
// split input to thousands
// 12_453_132_981 -> [12 453 132 981]
const maxThousands = 4
split := make([]int, maxThousands)
split[len(split)-1] = int(input) % 1000
for i := len(split) - 1; i >= 0; i-- {
split[len(split)-i-1] = int(input) / int(math.Pow10(i*3))
input = input % int64(math.Pow10(i*3))
}
// write splits one-by-one
var ret strings.Builder
for i, s := range split {
if s != 0 || // do not write empty thousands
// for the last one write zero if nothing is written yet
i == len(split)-1 && ret.Len() == 0 {
if ret.Len() != 0 {
ret.WriteRune(' ')
}
ret.WriteString(splitHandler(s) + thousandName[len(split)-i-1])
}
}
return ret.String(), true
}
func splitHandler(in int) string {
var ret strings.Builder
// handle the hundreds
if in > 99 {
ret.WriteString(tilTwenty[in/100] + " hundred")
if in%100 != 0 {
// we want to connect to hundred what is left if it is more than zero
ret.WriteRune(' ')
}
}
// under hundred part > 19
if in := in % 100; in > 19 {
ret.WriteString(tens[in/10])
if in%10 != 0 { // eg. twenty-two
ret.WriteString("-" + tilTwenty[in%10])
}
} else {
if in != 0 || ret.Len() == 0 { // non-zero or _only_ zero
ret.WriteString(tilTwenty[in%100])
}
}
return ret.String()
}