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: MEDIUM_HARD
Tags: String algorithms

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': 1000000}

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('(\\s|-|\\band)+')
SPLITTER = [re.compile(f'\\s*{what}\\s*') for what in ('million', 'thousand', 'hundred', '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())


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 ', ' '))