In this kata we want to convert a string into an integer. The strings simply represent the numbers in words.

Examples:

* "one" => 1
* "twenty" => 20
* "two hundred forty-six" => 246
* "seven hundred eighty-three thousand nine hundred and nineteen" => 783919

Additional Notes:

* The minimum number is "zero" (inclusively)
* The maximum number, which must be supported is 1 million (inclusively)
* The "and" in e.g. "one hundred and twenty-four" is optional, in some cases it's present and in others it's not
* All tested numbers are valid, you don't need to validate them

Difficulty: interview

Starter code:

def parse_int(string):
	

Solutions:
words = {w: n for n, w in enumerate('zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen'.split())}
words.update({w: 10 * n for n, w in enumerate('twenty thirty forty fifty sixty seventy eighty ninety hundred'.split(), 2)})
thousands = {w: 1000 ** n for n, w in enumerate('thousand million billion trillion quadrillion quintillion sextillion septillion octillion nonillion decillion'.split(), 1)}
def parse_int(strng):
    num = group = 0
    for w in strng.replace(' and ', ' ').replace('-', ' ').split():
        if w == 'hundred': group *= words[w]
        elif w in words: group += words[w]
        else:
            num += group * thousands[w]
            group = 0
    return num + group

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']

def parse_int(string):
    print(string)
    numbers = []
    for token in string.replace('-', ' ').split(' '):
        if token in ONES:
            numbers.append(ONES.index(token))
        elif token in TENS:
            numbers.append((TENS.index(token) + 2) * 10)
        elif token == 'hundred':
            numbers[-1] *= 100
        elif token == 'thousand':
            numbers = [x * 1000 for x in numbers]
        elif token == 'million':
            numbers = [x * 1000000 for x in numbers]
    return sum(numbers)

dic = {'zero'          : 0,    
       'one'           : 1,   
       'two'           : 2,   
       'three'         : 3,     
       'four'          : 4,    
       'five'          : 5,    
       'six'           : 6,   
       'seven'         : 7,     
       'eight'         : 8,     
       'nine'          : 9,    
       'ten'           : 10,           
       'eleven'        : 11,      
       'twelve'        : 12,      
       'thirteen'      : 13,        
       'fourteen'      : 14,        
       'fifteen'       : 15,       
       'sixteen'       : 16,       
       'seventeen'     : 17,         
       'eighteen'      : 18,        
       'nineteen'      : 19,        
       'twenty'        : 20,      
       'twenty-one'   : 21,           
       'twenty-two'   : 22,           
       'twenty-three' : 23,             
       'twenty-four'  : 24,            
       'twenty-five'  : 25,            
       'twenty-six'   : 26,           
       'twenty-seven' : 27,             
       'twenty-eight' : 28,             
       'twenty-nine'  : 29,            
       'thirty'        : 30,      
       'thirty-one'   : 31,           
       'thirty-two'   : 32,           
       'thirty-three' : 33,             
       'thirty-four'  : 34,            
       'thirty-five'  : 35,            
       'thirty-six'   : 36,           
       'thirty-seven' : 37,             
       'thirty-eight' : 38,             
       'thirty-nine'  : 39,            
       'forty'         : 40,     
       'forty-one'     : 41,         
       'forty-two'     : 42,         
       'forty-three'  : 43,            
       'forty-four'   : 44,           
       'forty-five'   : 45,           
       'forty-six'     : 46,         
       'forty-seven'  : 47,            
       'forty-eight'  : 48,            
       'forty-nine'   : 49,           
       'fifty'         : 50,     
       'fifty-one'     : 51,         
       'fifty-two'     : 52,         
       'fifty-three'  : 53,            
       'fifty-four'   : 54,           
       'fifty-five'   : 55,           
       'fifty-six'     : 56,         
       'fifty-seven'  : 57,            
       'fifty-eight'  : 58,            
       'fifty-nine'   : 59,           
       'sixty'         : 60,     
       'sixty-one'     : 61,         
       'sixty-two'     : 62,         
       'sixty-three'  : 63,            
       'sixty-four'   : 64,           
       'sixty-five'   : 65,           
       'sixty-six'     : 66,         
       'sixty-seven'  : 67,            
       'sixty-eight'  : 68,            
       'sixty-nine'   : 69,           
       'seventy'       : 70,       
       'seventy-one'  : 71,            
       'seventy-two'  : 72,            
       'seventy-three': 73,              
       'seventy-four' : 74,             
       'seventy-five' : 75,             
       'seventy-six'  : 76,            
       'seventy-seven': 77,              
       'seventy-eight': 78,              
       'seventy-nine' : 79,             
       'eighty'        : 80,      
       'eighty-one'   : 81,           
       'eighty-two'   : 82,           
       'eighty-three' : 83,             
       'eighty-four'  : 84,            
       'eighty-five'  : 85,            
       'eighty-six'   : 86,           
       'eighty-seven' : 87,             
       'eighty-eight' : 88,             
       'eighty-nine'  : 89,            
       'ninety'        : 90,      
       'ninety-one'   : 91,           
       'ninety-two'   : 92,           
       'ninety-three' : 93,             
       'ninety-four'  : 94,            
       'ninety-five'  : 95,            
       'ninety-six'   : 96,           
       'ninety-seven' : 97,             
       'ninety-eight' : 98,             
       'ninety-nine'  : 99,
       'hundred'      : 100,
       'thousand'      : 1000,
       'million'       : 1000_000,}

def parse_int(s):
    cn, res = 0, 0
    for number in (dic[w] for w in s.replace(' and','').split() if w in dic):
        if   number <  100: cn += number
        elif number == 100: cn *= number
        else              : res += cn * number; cn = 0
    return res + cn

def parse_int(string):
    
    print(string)
    
    setDigit = {"zero"      :0,
                "one"       :1,
                "two"       :2,
                "three"     :3,
                "four"      :4,
                "five"      :5,
                "six"       :6,
                "seven"     :7,
                "eight"     :8,
                "nine"      :9,
                "ten"       :10,
                "eleven"    :11,
                "twelve"    :12,
                "thirteen"  :13,
                "fourteen"  :14,
                "fifteen"   :15,
                "sixteen"   :16,
                "seventeen" :17,
                "eighteen"  :18,
                "nineteen"  :19,
                "twenty"    :20,
                "thirty"    :30,
                "forty"     :40,
                "fifty"     :50,
                "sixty"     :60,
                "seventy"   :70,
                "eighty"    :80,
                "ninety"    :90,
                }
     
     
    millionNumber, thousandNumber, hundredNumber, number = (0,) * 4
       
    for word in string.split():
        for newWord in word.split('-'):     
            
            try:
                digit = setDigit[newWord]
                number += digit
            except:
                
                if newWord == "hundred":
                    hundredNumber = number
                    number = 0
                    
                if newWord == "thousand":
                    thousandNumber = 100 * hundredNumber + number
                    hundredNumber = 0
                    number = 0
                    
                if newWord == "million":
                    millionNumber = number
                    number = 0
          
    return(millionNumber * 1000000 + thousandNumber * 1000 + hundredNumber * 100 + number)
        


import re

SIMPLIFIER = re.compile(r'(\s|-|\band)+')
SPLITTER   = [re.compile(rf'\s*{what}\s*') for what in ('million', 'thousand', 'hundred', r'ty\b')]
COEFS      = [10**x for x in (6,3,2,1)]

vals       = "zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split()
VALUES     = {name:v for name,v in zip(vals, range(len(vals)))}
VALUES.update({'twen': 2, 'thir': 3, 'for': 4, 'fif': 5, 'eigh':8})


def parse_int(s): 
    return parse(0, SIMPLIFIER.sub(' ',s.lower()))

def parse(i, s):
    if i == len(SPLITTER): return VALUES.get(s,0)
        
    lst, coef, i = SPLITTER[i].split(s), COEFS[i], i+1
    
    return parse(i,lst[0]) if len(lst)==1 else coef * parse(i,lst[0]) + parse(i,lst[1])

VALUES = {
    'zero': 0,
    'one': 1,
    'two': 2,
    'three': 3,
    'four': 4,
    'five': 5,
    'six': 6,
    'seven': 7,
    'eight': 8,
    'nine': 9,
    'ten': 10,
    'eleven': 11,
    'twelve': 12,
    'thirteen': 13,
    'fourteen': 14,
    'fifteen': 15,
    'sixteen': 16,
    'seventeen': 17,
    'eighteen': 18,
    'nineteen': 19,
    'twenty': 20,
    'thirty': 30,
    'forty': 40,
    'fifty': 50,
    'sixty': 60,
    'seventy': 70,
    'eighty': 80,
    'ninety': 90,
}


def parse_int(string):    
    if not string:
        return 0

    if string == 'one million':
        return 1000000

    if string in VALUES:
        return VALUES[string]

    if 'thousand' in string:
        before, after = split(string, 'thousand and') if 'thousand and' in string else split(string, 'thousand')
        factor = 1000
    elif 'hundred' in string:
        before, after = split(string, 'hundred and') if 'hundred and' in string else split(string, 'hundred')
        factor = 100
    elif '-' in string:
        before, after = split(string, ' ') if ' ' in string else split(string, '-')
        factor = 1

    return parse_int(before) * factor + parse_int(after)
        

def split(string, separator):
    before, after = string.rsplit(separator, 1)
    return before.strip(), after.strip()

number_words = {'': 0, 'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6,
        'seven': 7, 'eight': 8, 'nine': 9, 'ten': 10, 'eleven': 11, 'twelve': 12, 'thirteen': 13,
        'fourteen': 14, 'fifteen': 15, 'sixteen': 16, 'seventeen': 17, 'eighteen': 18,
        'nineteen': 19, 'twenty': 20,  'thirty': 30, 'forty': 40, 'fifty': 50, 'sixty': 60,
        'seventy': 70, 'eighty': 80, 'ninety': 90, 'one million': 1000000}

def parse_int(string):
    string_words = string.split()
    if 'thousand' in string_words:
        parts = string.partition('thousand')
        return parse_int(parts[0].strip()) * 1000 + parse_int(parts[2].strip())
    elif 'hundred' in string_words:
        parts = string.partition('hundred')
        return parse_int(parts[0].strip()) * 100 + parse_int(parts[2].strip())
    elif '-' in string:
        parts = string.replace('and ', '').split('-')
        return number_words[parts[0]] + number_words[parts[1]]
    else:
        return number_words[string.replace('and ', '')]

from functools import reduce
def parse_int(string):
    unit_ts={'zero':0,'one':1,'two':2,'three':3,'four':4,'five':5,'six':6,'seven':7,'eight':8,'nine':9,'ten':10,'eleven':11,'twelve':12,'thirteen':13,'fourteen':14,'fifteen':15,'sixteen':16,'seventeen':17,'eighteen':18,'nineteen':19,'twenty':20,'thirty':30,'forty':40,'fifty':50,'sixty':60,'seventy':70,'eighty':80,'ninety':90,'hundred':100,'thousand':1000,'million':1000000,'billion':1000000000}
    text=string.split(' ')
    lst=[]
    for element in text:
        if '-' in element:lst.append(unit_ts[element.split('-')[0]]+unit_ts[element.split('-')[1]])
        elif element in unit_ts:lst.append(unit_ts[element])
    myid=lst.index(max(lst))
    result=0
    result+=reduce(lambda x,y:x*y if y%100==0 else x+y,lst[:myid+1])if lst[:myid+1]!=[] else 0
    result+=reduce(lambda x,y:x*y if y%100==0 else x+y,lst[myid+1:])if lst[myid+1:]!=[] else 0
    return result

def parse_int(string):
    units = [
        "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"]
    
    string = string.replace('-', ' ')
    string = string.replace(' and ',' ')
    words = string.split()
    ans = 0
    final_ans = 0
    
    for word in words:
        if word in units: ans += units.index(word)
        elif word in tens: ans += tens.index(word)*10
        elif word == 'hundred': ans *= 100
        elif word == 'thousand': final_ans,ans = ans*1000, 0
        elif word == 'million': return 1000000
    final_ans += ans    
    return final_ans


conv={
      "zero":        0,
      "one":         1,
      "two":         2,
      "three":       3,
      "four":        4,
      "five":        5,
      "six":         6,
      "seven":       7,
      "eight":       8,
      "nine":        9,
      "ten":        10,
      "eleven":     11,
      "twelve":     12,
      "thirteen":   13,
      "fourteen":   14,
      "fifteen":    15,
      "sixteen":    16,
      "seventeen":  17,
      "eighteen":   18,
      "nineteen":   19,
      "twenty":     20,
      "thirty":     30,
      "forty":      40,
      "fifty":      50,
      "sixty":      60,
      "seventy":    70,
      "eighty":     80,
      "ninety":     90,
      "hundred":   100,
      "thousand": 1000,
      "million":  1000000
      }


def parse99(s: str):
    num = 0
    for wd in s.split("-"): num += conv.get(wd.strip(), 0)
    return num
    

def parseHundreds(s: str):
    s = s.split("hundred")
    if len(s) == 1:
        return parse99(s[0])
    else:
        return parse99(s[0])*100 + parse99(s[1])
    

def parseThousands(s: str):
    s = s.split("thousand")
    if len(s) == 1:
        return parseHundreds(s[0])
    else:
        return parseHundreds(s[0])*1000 + parseHundreds(s[1]) 
    
def parseMillions(s: str):
    s = s.split("million")
    if len(s) == 1:
        return parseThousands(s[0])
    else:
        return parseThousands(s[0])*1000000 + parseThousands(s[1]) 

def parse_int(s: str):
    #
    return parseMillions(s.replace(" and "," "))