patternjavascriptMinor
Naming numbers in American English
Viewed 0 times
numbersenglishamericannaming
Problem
This seems like a popular topic lately, so I took a crack at it.
Related questions are Number to Words and Converting a number to the text representation.
I used this article as a guideline. The article mostly explains by example, but some key points were:
-
Use a hyphen to separate numbers like twenty-two.
-
Using and is not a requirement, so 2014 can be written as two thousand fourteen.
-
No use of commas is mentioned, other than as placeholders in numbers represented with numerals.
It mentions that numbers may be spoken like two thousand and fourteen in the last footnote; maybe this could be an optional feature added later. If someone finds a better reference showing that any of this is incorrect, please let me know.
```
(function (global) {
'use strict';
var scalePrefix = ['m', 'b', 'tr', 'quadr', 'quint',
'sext', 'sept', 'oct', 'non', 'dec'];
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: 'thir', 5: 'fif', 8: 'eigh' };
function nameDigit(digit) {
return digits[digit];
}
function nameTenToNineteen(number) {
var prefix = teens[number] || digits[number];
return number scalePrefix.length + 2) {
throw new Error('number out of range: ' + number);
}
return symbols;
}
function nameNumber(number) {
var symbols = extractSymbols(number),
sign = '',
segments = [],
segment;
function append(item) {
item && segments.push(item);
}
if (symbols[0] == '-') {
sign = 'negative ';
symbols.shift();
}
while (symbols.length % 3) {
symbols.unshift(0);
}
while (symbols.length) {
Related questions are Number to Words and Converting a number to the text representation.
I used this article as a guideline. The article mostly explains by example, but some key points were:
-
Use a hyphen to separate numbers like twenty-two.
-
Using and is not a requirement, so 2014 can be written as two thousand fourteen.
-
No use of commas is mentioned, other than as placeholders in numbers represented with numerals.
It mentions that numbers may be spoken like two thousand and fourteen in the last footnote; maybe this could be an optional feature added later. If someone finds a better reference showing that any of this is incorrect, please let me know.
```
(function (global) {
'use strict';
var scalePrefix = ['m', 'b', 'tr', 'quadr', 'quint',
'sext', 'sept', 'oct', 'non', 'dec'];
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: 'thir', 5: 'fif', 8: 'eigh' };
function nameDigit(digit) {
return digits[digit];
}
function nameTenToNineteen(number) {
var prefix = teens[number] || digits[number];
return number scalePrefix.length + 2) {
throw new Error('number out of range: ' + number);
}
return symbols;
}
function nameNumber(number) {
var symbols = extractSymbols(number),
sign = '',
segments = [],
segment;
function append(item) {
item && segments.push(item);
}
if (symbols[0] == '-') {
sign = 'negative ';
symbols.shift();
}
while (symbols.length % 3) {
symbols.unshift(0);
}
while (symbols.length) {
Solution
Interesting question, impressive code.
I only found one thing that could be considered a bug:
Other than that I think you went a little overboard in some places to achieve the ultimate DRYness.
This:
(ignore the removed newlines) puts the
The same ( though I am not sure this would reduce character count here ) can be said for
Note how it sneakily removes an offensive ternary :P It would also no longer require the magical
In
The same goes for
One last item is
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 milllion, billion etc. If you were to add '', 'thousand' and 'illion' at the end of existing entries, then your nameTripletScale could befunction 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.Code Snippets
if (!number.match(/^(-?)[\d,]+$/)) {
throw new Error('invalid number: ' + number);
}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';
}function nameTripletScale(digitCount) {
return scalePrefix[digitCount / 3 ];
}Context
StackExchange Code Review Q#58939, answer score: 7
Revisions (0)
No revisions yet.