nuVistA/htdocs/numberwords.mjs

57 lines
3.0 KiB
JavaScript
Raw Normal View History

2023-04-24 23:10:19 -04:00
function pos_int2words(n,
ones=['' ,'one' ,'two' ,'three' ,'four' ,'five' ,'six' ,'seven' ,'eight' ,'nine'],
teens=['ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'],
tens=['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']) {
if(n < 10) return ones[n];
else if(n < 20) return teens[n - 10];
else if(n < 100) return tens[Math.floor(n/10)] + (n%10 > 0 ? '-' + ones[n%10] : '');
else if(n < 1000) return ones[Math.floor(n/100)] + ' hundred ' + pos_int2words(n%100);
else if(n < 1000000) return pos_int2words(Math.floor(n/1000)) + ' thousand ' + pos_int2words(n%1000);
else return pos_int2words(Math.floor(n/1000000)) + ' million ' + pos_int2words(n%1000000);
}
export function int2words(n,
ones=['' ,'one' ,'two' ,'three' ,'four' ,'five' ,'six' ,'seven' ,'eight' ,'nine'],
teens=['ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'],
tens=['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']) {
if(n == 0) return 'zero';
else if(n < 0) return 'negative ' + pos_int2words(n, ones, teens, tens).replace(/\s+$/, '');
else return pos_int2words(n, ones, teens, tens).replace(/\s+$/, '');
}
export function cardinal2ordinal(s, re_magnitudes=/(hundred|thousand|(m|b|tr|quadr)illion)$/, re_low=/(zero|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)$/, ordinals={ zero: 'zeroth', one: 'first', two: 'second', three: 'third', four: 'fourth', five: 'fifth', six: 'sixth', seven: 'seventh', eight: 'eighth', nine: 'ninth', ten: 'tenth', eleven: 'eleventh', twelve: 'twelfth' }) {
if((s.slice(-4) == 'teen') || (re_magnitudes.test(s))) return s + 'th';
else if(s.charAt(s.length - 1) == 'y') return s.substring(0, s.length - 1) + 'ieth';
else return s.replace(re_low, (m, w) => ordinals[w]);
}
export function float2fraction(x, epsilon=0.0001) {
if(x == 0) return [0, 1];
const a = Math.abs(x);
let n = 0, d = 1, r;
while(Math.abs((r = n/d) - a)/a >= epsilon) if(r < a) n++;
else d++;
return [x < 0 ? -n : n, d];
}
function pos_fraction2words(x, epsilon=0.0001) {
const frac = float2fraction(x, epsilon), n = frac[0], d = frac[1];
if(d == 1) return int2words(x);
else if(d == 2) return int2words(n) + (n >= 2 ? ' halves' : ' half');
else if(d == 4) return int2words(n) + (n >= 2 ? ' quarters' : ' quarter');
else return int2words(n) + ' ' + cardinal2ordinal(int2words(d)) + (n >= 2 ? 's' : '');
}
export function num2words(n, epsilon=0.0001) {
if(n == 0) return 'zero';
else if(n < 0) return 'negative ' + num2words(-n);
var intpart = n|0;
if(n == intpart) return int2words(n);
else if(intpart == 0) return pos_fraction2words(n, epsilon);
else return num2words(intpart) + ' and ' + pos_fraction2words(n%1, epsilon);
}
export function translate(s, epsilon=0.0001) {
return ('' + s).replace(/([+-]?(?:\d+|\d+\.\d+))/g, (m, w) => num2words(w, epsilon));
}