2,549 bytes · the Python implementation · view raw
from typing import Any, List
#: Largest integer a JavaScript number holds exactly; beyond it the three#: languages disagree about what number was passed.
MAX_MAGNITUDE = 9007199254740991
_ONES = [
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
"seventeen", "eighteen", "nineteen",
]
_TENS = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
#: Short scale, as used in the UK since 1974: a billion is 10^9.
_SCALES = ["", "thousand", "million", "billion", "trillion", "quadrillion"]
def _below_hundred(n: int) -> str:
if n < 20:
return _ONES[n]
unit = n % 10return _TENS[n // 10] if unit == 0else"%s-%s" % (_TENS[n // 10], _ONES[unit])
def _group(n: int) -> str:
"""One group of three digits, 1 to 999."""
hundreds, rest = divmod(n, 100)
if hundreds == 0:
return _below_hundred(rest)
head = "%s hundred" % _ONES[hundreds]
return head if rest == 0else"%s and %s" % (head, _below_hundred(rest))
def _whole(value: Any) -> bool:
# bool is an int in Python; True is not the number one here.return isinstance(value, int) andnot isinstance(value, bool)
def integer_to_words(value: int) -> str:
"""Spell out a whole number in British English words, cheque style: 1234 is "one thousand two hundred and thirty-four". """ifnot _whole(value):
raise TypeError("integerToWords needs a whole number, received %r" % (value,))
if value > MAX_MAGNITUDE or value < -MAX_MAGNITUDE:
raise ValueError(
"%d is out of range: integerToWords handles magnitudes up to %d" % (value, MAX_MAGNITUDE)
)
if value == 0:
return"zero"# Groups of three, least significant first.
groups: List[int] = []
remaining = abs(value)
while remaining > 0:
groups.append(remaining % 1000)
remaining //= 1000
words: List[str] = []
for i in range(len(groups) - 1, -1, -1):
g = groups[i]
if g == 0:
continue
text = _group(g)
if i > 0:
text += " " + _SCALES[i]
elif len(groups) > 1and g < 100:
# British usage: "one thousand and one", "one million and fifty".# Only the final group gets it, and only without hundreds of its own.
text = "and " + text
words.append(text)
body = " ".join(words)
return"minus " + body if value < 0else body