Developed around chain of responsibilities design pattern, it consists of a series of converters returning arrays of string that could be used either to look up text mapped to the keys, for internationalisation, or to display the literary form of numbers.
var formatter = (mapper) => {
return (outputer) => {
return (formattee) => {
var input = "" + formattee;
return outputer((mapper(input)));
};
};
};
var zeroless = { until : (length) => {
var unpad = (unpadded) => {
var returnee = "";
for ( var i = 0; i < unpadded.length; i++) {
if (unpadded.charAt(i) == 0) { continue; }
returnee = returnee + unpadded.charAt(i);
}
return returnee;
};
return (unpadded) => unpad(unpadded);
}};
var rounded = { division : (dividend, divisor) => Math.floor(dividend/divisor) };
var unitary = (function() {
return formatter((text) => {
var symbol = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"];
return [ symbol[text] ];
}); })();
var tens = (function() {
return formatter((text) => {
var unit = unitary(t => t);
if (text.length == 2 && text.charAt(0) == 0) {
return unit(text.charAt(1));
}
if (text.length == 1) { return unit(text); }
var symbol = ["", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninty"];
var overwrite = ["", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
var first = text.charAt(0);
var last = text.charAt(text.length - 1);
return (first == 1) ? (last == 0 ? [ symbol[first] ] : [ overwrite[last] ]) : [ symbol[first] ].concat(unit(last)).reduce((accumulator, element) => element.length > 0 ? accumulator.concat(element) : accumulator, []);
}); })();
var hundreds = formatter((text) => {
var ten = tens(t=>t);
var unit = unitary(t=>t);
if ( text.length == 3 && text.charAt(0) == 0) {
return ten(text.substring(1)).reduce((accumulator, element) => element.length > 0 ? accumulator.concat(element) : accumulator, []);;
}
var magnitude = "hundred" + (text.charAt(0) == 1 ? "" : "s");
return text.length < 3 ? ten(text) : unit(text.charAt(0)).concat([ magnitude ]).concat(ten(text.substring(1))).reduce((accumulator, element) => element.length > 0 ? accumulator.concat(element) : accumulator, []);
});
//100 000
var thousands = formatter((text) => {
;
var hundred = hundreds(t=>t);
var numeric = zeroless.until(3)(text);
if (numeric.length < 4) {
return hundred(numeric);
}
var start = "" + rounded.division(numeric, 1000);
var magnitude = "thousand" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(hundred(numeric.substring(start.length)));
});
//100 000 000
var millions = formatter((text) => {
var thousand = thousands(t=>t);
var numeric = zeroless.until(6)(text);
if (numeric.length < 7) {
return thousand(numeric);
}
var hundred = hundreds(t=>t);
var start = "" + rounded.division(numeric, 1000000);
var magnitude = "million" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(thousand(text.substring(start.length)));
});
//100 000 000 000
var billions = formatter((text) => {
var million = millions(t=>t);
var numeric = zeroless.until(9)(text);
if (numeric.length < 10) {
return million(numeric);
}
var hundred = hundreds(t=>t);
var start = "" + rounded.division(numeric, 1000000000);
var magnitude = "billion" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(million(text.substring(start.length)));
});
//100 000 000 000 000
var quadrillions = formatter((text) => {
var billion = billions(t=>t);
var numeric = zeroless.until(12)(text);
if (numeric.length < 13) {
return billion(numeric);
}
var hundred = hundreds(t=>t);
var start = "" + rounded.division(numeric, 1000000000000);
var magnitude = "quadrillion" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(billion(text.substring(start.length)));
});
//100 000 000 000 000 000
var quintillions = formatter((text) => {
var quadrillion = quadrillions(t=>t);
var numeric = zeroless.until(15)(text);
if (numeric.length < 16) {
return quadrillion(numeric);
}
var hundred = hundreds(t=>t);
var start = "" + rounded.division(numeric, 1000000000000000);
var magnitude = "quintillion" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(quadrillion(text.substring(start.length)));
});
…for English language the usage could be…
var translate = { numerical : quintillions(text => {
var en = { one: "one"
, two: "two"
, three: "three"
, four: "four"
, five: "five"
, six: "six"
, seven: "seven"
, eight: "eight"
, nine: "nine"
, ten: "ten"
, twenty: "twenty"
, thirty: "thirty"
, forty: "forty"
, fifty: "fifty"
, sixty: "sisty"
, seventy: "seventy"
, eighty: "eighty"
, ninty: "ninty"
, eleven: "eleven"
, twelve: "twelve"
, thirteen: "thirteen"
, fourteen: "fourteen"
, fifteen: "fifteen"
, sixteen: "sixteen"
, seventeen: "seventeen"
, eighteen: "eighteen"
, nineteen: "nineteen"
, hundred: "hundred"
, hundreds: "hundreds"
, thousand: "thousand"
, thousands: "thousands"
, million: "million"
, millions: "millions"
, billion: "billion"
, billions: "billions"
, quadrillion: "quadrillion"
, quadrillions: "quadrillions"
, quintillion: "quintillion"
, quintillions: "quintillions"
,
};
var value = text.map(key => en[key]).join(" ");
console.log(value);
})};
translate.numerical(1234567890);
…while a more complex usage setup, that is out of scope for hereby code review request, could be…
<html>
<head>
<title>Translate numerical...</title>
<style type="text/css">
.side {
background-color: #fff;
float: left;
height: 100%;
}
.field { color: #777; }
.field::placeholder { color: #dedede; }
.message { color: #777; }
.paper { margin-right: 2px; text-align: center; width: 15%; }
.paper .field { width: 98%; }
.paper .field , .board .message {
background-color: #fff;
border: 0;
height: 25px;
line-height: 25px;
font-size: 15px;
}
.board { width: 84%; }
.board .message { text-align: center; width: 99%;}
</style>
<script type="text/javascript">
var formatter = (mapper) => {
return (outputer) => {
return (formattee) => {
var input = "" + formattee;
return outputer((mapper(input)));
};
};
};
var zeroless = { until : (length) => {
var unpad = (unpadded) => {
var returnee = "";
for ( var i = 0; i < unpadded.length; i++) {
if (unpadded.charAt(i) == 0) { continue; }
returnee = returnee + unpadded.charAt(i);
}
console.log("returnee: " + returnee);
return returnee;
};
return (unpadded) => unpad(unpadded);
}};
var rounded = { division : (dividend, divisor) => Math.floor(dividend/divisor) };
var unitary = (function() {
return formatter((text) => {
var symbol = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"];
return [ symbol[text] ];
}); })();
var tens = (function() {
return formatter((text) => {
var unit = unitary(t => t);
if (text.length == 2 && text.charAt(0) == 0) {
return unit(text.charAt(1));
}
if (text.length == 1) { return unit(text); }
var symbol = ["", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninty"];
var overwrite = ["", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
var first = text.charAt(0);
var last = text.charAt(text.length - 1);
return (first == 1) ? (last == 0 ? [ symbol[first] ] : [ overwrite[last] ]) : [ symbol[first] ].concat(unit(last)).reduce((accumulator, element) => element.length > 0 ? accumulator.concat(element) : accumulator, []);
}); })();
var hundreds = formatter((text) => {
var ten = tens(t=>t);
var unit = unitary(t=>t);
if ( text.length == 3 && text.charAt(0) == 0) {
return ten(text.substring(1)).reduce((accumulator, element) => element.length > 0 ? accumulator.concat(element) : accumulator, []);;
}
var magnitude = "hundred" + (text.charAt(0) == 1 ? "" : "s");
return text.length < 3 ? ten(text) : unit(text.charAt(0)).concat([ magnitude ]).concat(ten(text.substring(1))).reduce((accumulator, element) => element.length > 0 ? accumulator.concat(element) : accumulator, []);
});
//100 000
var thousands = formatter((text) => {
;
var hundred = hundreds(t=>t);
var numeric = zeroless.until(3)(text);
if (numeric.length < 4) {
return hundred(numeric);
}
var start = "" + rounded.division(numeric, 1000);
var magnitude = "thousand" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(hundred(numeric.substring(start.length)));
});
//100 000 000
var millions = formatter((text) => {
var thousand = thousands(t=>t);
var numeric = zeroless.until(6)(text);
if (numeric.length < 7) {
return thousand(numeric);
}
var hundred = hundreds(t=>t);
var start = "" + rounded.division(numeric, 1000000);
var magnitude = "million" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(thousand(text.substring(start.length)));
});
//100 000 000 000
var billions = formatter((text) => {
var million = millions(t=>t);
var numeric = zeroless.until(9)(text);
if (numeric.length < 10) {
return million(numeric);
}
var hundred = hundreds(t=>t);
var start = "" + rounded.division(numeric, 1000000000);
var magnitude = "billion" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(million(text.substring(start.length)));
});
//100 000 000 000 000
var quadrillions = formatter((text) => {
var billion = billions(t=>t);
var numeric = zeroless.until(12)(text);
if (numeric.length < 13) {
return billion(numeric);
}
var hundred = hundreds(t=>t);
var start = "" + rounded.division(numeric, 1000000000000);
var magnitude = "quadrillion" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(billion(text.substring(start.length)));
});
//100 000 000 000 000 000
var quintillions = formatter((text) => {
var quadrillion = quadrillions(t=>t);
var numeric = zeroless.until(15)(text);
if (numeric.length < 16) {
return quadrillion(numeric);
}
var hundred = hundreds(t=>t);
var start = "" + rounded.division(numeric, 1000000000000000);
var magnitude = "quintillion" + ((start == 1) ? "" : "s");
return hundred(start).concat([ magnitude ]).concat(quadrillion(text.substring(start.length)));
});
var element = { of: (selector) => document.querySelector(selector) };
var elements = { of: (selector) => document.querySelectorAll(selector) };
var board = { on : (selector) => {
var bearer = document.querySelector(selector);
var container = { element : () => {
bearer = bearer == null ? document.querySelector(selector) : bearer;
return bearer;
}};
var createDiv = () => {
var div = document.createElement("div");
div.className = "message";
return div;
};
return { write : { message : (text) => {
var div = createDiv();
div.innerText = text;
container.element().innerHTML = "";
container.element().appendChild(div);
}
, clear : () => {
container.element().innerHTML = "";
}
}};}};
var display = board.on(".board");
var translate = { numerical : quintillions(text => {
var en = { one: "one"
, two: "two"
, three: "three"
, four: "four"
, five: "five"
, six: "six"
, seven: "seven"
, eight: "eight"
, nine: "nine"
, ten: "ten"
, twenty: "twenty"
, thirty: "thirty"
, forty: "forty"
, fifty: "fifty"
, sixty: "sisty"
, seventy: "seventy"
, eighty: "eighty"
, ninty: "ninty"
, eleven: "eleven"
, twelve: "twelve"
, thirteen: "thirteen"
, fourteen: "fourteen"
, fifteen: "fifteen"
, sixteen: "sixteen"
, seventeen: "seventeen"
, eighteen: "eighteen"
, nineteen: "nineteen"
, hundred: "hundred"
, hundreds: "hundreds"
, thousand: "thousand"
, thousands: "thousands"
, million: "million"
, millions: "millions"
, billion: "billion"
, billions: "billions"
, quadrillion: "quadrillion"
, quadrillions: "quadrillions"
, quintillion: "quintillion"
, quintillions: "quintillions"
,
};
var value = text.map(key => en[key]).join(" ");
display.write.message(value);
})};
var writable = () => {
var inputify = () => {
var maxLength = 17;
var input = document.createElement("input");
input.type = "text";
input.className = "field";
input.maxLength = maxLength;
input.placeholder = "max. length " + maxLength;
var change = (event) => {
var value = event.target.value;
if ( isNaN(value) ) {
return;
}
event.target.readonly = "readonly";
translate.numerical(value);
};
input.addEventListener("keyup", (event) => {
if ( event.keyCode != 13 ) { return; }
change(event);
});
input.addEventListener("change", (event) => {
if (event.target.value.trim().length == 0) { return; }
console.log("change");
change(event);
writable();
});
element.of(".paper").appendChild(input);
return input;
};
var inputs = elements.of(".paper input");
var input = inputs.length == 0 || inputs[inputs.length - 1].readonly == "readonly" ? inputify() : inputs[inputs.length - 1];
input.focus();
};
</script>
</head>
<body onload="writable()">
<div class="side paper" onclick="writable()"></div>
<div class="side board"></div>
</body>
</html>
While of interest are performance improvements, any feedback is welcomed.