<jupyter_start><jupyter_text>Display numbers in English Display a value like 112,305,260,623 as  "one hundred and twelve billion, "  "three hundred and five million, "  "two hundred and sixty thousand, "  "six hundred and twenty three"See [The example problem](https://leetcode.com/xxx/)<jupyter_code># %load TestHarness
debugging = False
debugging = True

debugging2 = False

logging = True


def dbg(f, *args):
    if debugging:
        print(('  DBG:' + f).format(*args))

def dbg2(f, *args):
    if debugging2:
        print(('  DBG2:' + f).format(*args))
        
def log(f, *args):
    if logging:
        print((f).format(*args))
        
def log_error(f, *args):
    if logging:
        print(('*** ERROR:' + f).format(*args))       
        
def class_name(instance):
    return type(instance).__name__

#------------------------------------------------------------------------------   
import time
from datetime import timedelta

#------------------------------------------------------------------------------
class TestCase(object):
    def __init__(self, name, method, inputs, expected, catchExceptions=False):
        self.name = name
        self.method = method
        self.inputs = inputs
        self.expected = expected
        self.catchExceptions = catchExceptions
        
    def run(self):
        if self.catchExceptions:
            try:
                return self.method(*self.inputs)
            except Exception as x:
                return x
        else:
                return self.method(*self.inputs)

#------------------------------------------------------------------------------
class TestSet(object):
    def __init__(self, cases):
        self.cases = cases
    
    def run_tests(self, repeat=1):
        count = 0
        errors = 0
        total_time = 0
        for case in self.cases:
            count += 1
            start_time = time.time()
            for iteration in range(repeat):
                dbg2("*** Running '{0}' iteration {1}", case.name, iteration+1)
                result = case.run()
            elapsed_time = time.time() - start_time
            total_time += elapsed_time
            if callable(case.expected):
                if not case.expected(result):
                    errors += 1
                    logError("Test {0} failed. Returned {1}", case.name, result)
            elif result != case.expected:
                errors += 1
                logError('Test {0} failed. Returned "{1}", expected "{2}"', case.name, result, case.expected)
        if errors:
            logError("Tests passed: {0}; Failures: {1}", count-errors, errors)
        else:
            log("All {0} tests passed.", count)
        log("Elapsed test time: {0}", timedelta(seconds=total_time))

        

def english_num(v):
    result = []
    if isinstance(v, str):
        v = int(v.replace(',', ''))
    
    def emit_symbol(s):
        nonlocal result
        result += s
        
    def emit_word(s):
        nonlocal result
        if len(result) > 0: result += ' '
        result += s
        
    def emit_scale(scale):
        ''' emit scale suffix (power of one thousand) '''
        assert scale>=1 and scale<=5
        w = "thousand million billion trillion quadrillion".split()
        emit_word(w[scale-1])
    
    def emit_digit(n):
        ''' emit a single digit, but ignore zero '''
        assert n >= 0 and n < 10
        w = "one two three four five six seven eight nine".split()
        if n>0: emit_word(w[n-1])
            
    def emit_teen(n):
        assert n >= 10 and n < 20
        w = "ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split()
        emit_word(w[n-10])

    def emit_by_tens(n):        
        assert n >= 2 and n <= 9
        w = "twenty thirty fourty fifty sixty seventy eighty ninety".split()
        emit_word(w[n-2])

    def emit_triplet(v, finalAnd=False):
        assert v>0 and v<999
        hundreds = v // 100
        v = v % 100
        if hundreds > 0:
            emit_digit(hundreds)
            emit_word('hundred')
            finalAnd = True
        if v > 0 and finalAnd: emit_word('and')        
        if v > 19:
            tens = v // 10
            v = v % 10
            emit_by_tens(tens)
            emit_digit(v)
        elif v > 9:
            emit_teen(v)
        else:
            emit_digit(v)
    
    finalAnd = False
    if v == 0:
        emit_word('zero')
    else:
        if v < 0: 
            emit_word('negative')
            v = -v
        for scale_index in range(5, 0, -1):
            scale_power = 1000**scale_index
            if v // scale_power > 0:
                emit_triplet(v // scale_power)
                emit_scale(scale_index)
                v = v % scale_power
                if v > 0: 
                    emit_symbol(',')
                    finalAnd = True
        emit_triplet(v, finalAnd)
    return ''.join(result)
print(english_num(0))
print(english_num(1))
print(english_num(-8))
print(english_num(-11223456334343442))
print(english_num('-100,223,456,334,343,442'))
print(english_num(20))
print(english_num(99))
print(english_num(100))
print(english_num(101))
print(english_num(10309021))
print(english_num(10309821))
print(english_num(10369821))
zrint(english_num('10,360,821'))
z = TestCase('zero', english_num, [0], 'zero')
TestSet([z]).run_tests()
case_number = 0
def Case(v, ex):
    global case_number
    case_number += 1
    nm = 'Test:' + str(case_number)   
    return TestCase(nm, english_num, [v], ex)

x = [Case(20, 'twenty'),
    Case(99, 'ninety nine'),
    Case(100, 'one hundred'),
    Case(101, 'one hundred and one'),
    Case(10309021, 'ten million, three hundred and nine thousand, and twenty one'),
    Case(10309821, 'ten million, three hundred and nine thousand, eight hundred and twenty one'),
    Case(10369821, 'ten million, three hundred and sixty nine thousand, eight hundred and twenty one'),
    Case('10,360,821', 'ten million, three hundred and sixty thousand, eight hundred and twenty one'),
    ]
TestSet(x).run_tests()<jupyter_output>All 8 tests passed.
Elapsed test time: 0:00:00.000274
{'fraction_non_alphanumeric': 0.1527551353113792, 'fraction_numerical': 0.03602869253342028, 'mean_word_length': 1.8574755472752678, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 17, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '263033', 'license': 'Unlicense', 'n_tokens_mistral': 1967, 'n_tokens_neox': 1794, 'n_words': 512, 'path': 'EnglishMath.ipynb', 'repo_name': 'jfogarty/python-code-practice', 'size': '6134'}