Interesting question, impressive code.
I only found one thing that could be considered a bug:
nameNumber('15.000')
will return "one hundred fiftyundefined thousand", this could be fixed by changing your regex to
if (!number.match(/^(-?)[\d,]+$/)) {
throw new Error('invalid number: ' + number);
}
Other than that I think you went a little overboard in some places to achieve the ultimate DRYness.
This:
var digits = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
var tens = ['', 'ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
var teens = { 0: 'ten', 1: 'eleven', 2: 'twelve', 3: 'thirteen', 5: 'fifteen', 8: 'eighteen' };
function nameDigit(digit) {
return digits[digit];
}
function nameTenToNineteen(number) {
return teens[number] || digits[number] + 'teen';
}
(ignore the removed newlines) puts the 'teen'
back in the teens
array, you no longer need a temporary variable or encode that you do not have the add 'teen'
for 10,11 and 12. This has less characters, and less complexity.
The same ( though I am not sure this would reduce character count here ) can be said for scalePrefix
, it took me a while to figure that this was supposed to return m
illlion, b
illion etc. If you were to add ''
, 'thousand'
and 'illion'
at the end of existing entries, then your nameTripletScale
could be
function nameTripletScale(digitCount) {
return scalePrefix[digitCount / 3 ];
}
Note how it sneakily removes an offensive ternary :P It would also no longer require the magical +2
in if (digitCount / 3 > scalePrefix.length + 2) {
In extractSymbols
you mix parsing, conversion, validation and error handling, I usually don't like that but the code is succinct enough that I can not offer a reasonable alternative.
The same goes for function append(item) {
in nameNumber
, it looks a bit busy but removing it looks worse.
One last item is nameDigit(digit)
, it requires more characters than say digits[digit]
and about half of the time you actually use direct array access instead of calling nameDigit
, I would just drop nameDigit
entirely.