diff --git a/speller/speller.go b/speller/speller.go index b1f50f5..9bafdad 100644 --- a/speller/speller.go +++ b/speller/speller.go @@ -2,6 +2,87 @@ package speller -func Spell(n int64) string { - return "" +import ( + "strings" +) + +var numToDigits = []string{ + "", "one", "two", "three", "four", "five", + "six", "seven", "eight", "nine", +} + +var teens = []string{ + "ten", "eleven", "twelve", "thirteen", "fourteen", + "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", +} + +var decs = []string{ + "", "", "twenty", "thirty", "forty", "fifty", + "sixty", "seventy", "eighty", "ninety", +} + +var large = []string{ + "billion", "million", "thousand", +} + +func digitsReversedSlice(n int64) []uint8 { + digits := make([]uint8, 12) + for i := 0; i < len(digits); i, n = i+1, n/10 { + digits[i] = uint8(n % 10) + } + return digits +} + +func Spell(n int64) string { + if n == 0 { + return "zero" + } + sign := n < 0 + if sign { + n = -n + } + num, digits := strings.Builder{}, digitsReversedSlice(n) + // 35 is the optimal number which gives approx needed + // space for the number in 1 allocation + num.Grow(len(digits) * 35) + if sign { + num.WriteString("minus ") + } + largeIndex, iters := 0, 0 + for i := len(digits) - 1; i >= 0; i, largeIndex = i-3, largeIndex+1 { + first, second, third := digits[i-2], digits[i-1], digits[i] + if first == 0 && second == 0 && third == 0 { + continue + } + if iters != 0 { + num.WriteRune(' ') + } + hundreds := numToDigits[third] + if hundreds != "" { + num.WriteString(hundreds) + num.WriteString(" hundred") + if second != 0 || first != 0 { + num.WriteRune(' ') + } + } + if second > 1 { + num.WriteString(decs[second]) + if first > 0 { + num.WriteRune('-') + num.WriteString(numToDigits[first]) + } + } else if second == 1 { + num.WriteString(teens[first]) + } else { + if first > 0 { + num.WriteString(numToDigits[first]) + } + } + if largeIndex < len(large) { + num.WriteRune(' ') + num.WriteString(large[largeIndex]) + } + iters++ + } + return num.String() }