57 lines
3.0 KiB
JavaScript
57 lines
3.0 KiB
JavaScript
|
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));
|
||
|
}
|