NUM = {
    # FR
    "zéro": 0,
    "un": 1,
    "deux": 2,
    "trois": 3,
    "quatre": 4,
    "cinq": 5,
    "six": 6,
    "sept": 7,
    "huit": 8,
    "neuf": 9,
    "dix": 10,
    "onze": 11,
    "douze": 12,
    "treize": 13,
    "quatorze": 14,
    "quinze": 15,
    "seize": 16,
    "dix-sept": 17,
    "dix-huit": 18,
    "dix-neuf": 19,
    "vingt": 20,
    "vingt-et-un": 21,
    "vingt et un": 21,
    "vingt-deux": 22,
    "vingt-trois": 23,
    "vingt-quatre": 24,
    "vingt-cinq": 25,
    "vingt-six": 26,
    "vingt-sept": 27,
    "vingt-huit": 28,
    "vingt-neuf": 29,
    "trente": 30,
    "trente-et-un": 31,
    "trente-deux": 32,
    "trente-trois": 33,
    "trente-quatre": 34,
    "trente-cinq": 35,
    "trente-six": 36,
    "trente-sept": 37,
    "trente-huit": 38,
    "trente-neuf": 39,
    "quarante": 40,
    "quarante-et-un": 41,
    "quarante-deux": 42,
    "quarante-trois": 43,
    "quarante-quatre": 44,
    "quarante-cinq": 45,
    "quarante-six": 46,
    "quarante-sept": 47,
    "quarante-huit": 48,
    "quarante-neuf": 49,
    "cinquante": 50,
    "cinquante-et-un": 51,
    "cinquante-deux": 52,
    "cinquante-trois": 53,
    "cinquante-quatre": 54,
    "cinquante-cinq": 55,
    "cinquante-six": 56,
    "cinquante-sept": 57,
    "cinquante-huit": 58,
    "cinquante-neuf": 59,
    "soixante": 60,
    "soixante-et-un": 61,
    "soixante-deux": 62,
    "soixante-trois": 63,
    "soixante-quatre": 64,
    "soixante-cinq": 65,
    "soixante-six": 66,
    "soixante-sept": 67,
    "soixante-huit": 68,
    "soixante-neuf": 69,
    "soixante-dix": 70,
    "soixante-et-onze": 71,
    "soixante-douze": 72,
    "soixante-treize": 73,
    "soixante-quatorze": 74,
    "soixante-quinze": 75,
    "soixante-seize": 76,
    "soixante-dix-sept": 77,
    "soixante-dix-huit": 78,
    "soixante-dix-neuf": 79,
    "quatre-vingts": 80,
    "quatre-vingt-un": 81,
    "quatre-vingt-deux": 82,
    "quatre-vingt-trois": 83,
    "quatre-vingt-quatre": 84,
    "quatre-vingt-cinq": 85,
    "quatre-vingt-six": 86,
    "quatre-vingt-sept": 87,
    "quatre-vingt-huit": 88,
    "quatre-vingt-neuf": 89,
    "quatre-vingt-dix": 90,
    "quatre-vingt-onze": 91,
    "quatre-vingt-douze": 92,
    "quatre-vingt-treize": 93,
    "quatre-vingt-quatorze": 94,
    "quatre-vingt-quinze": 95,
    "quatre-vingt-seize": 96,
    "quatre-vingt-dix-sept": 97,
    "quatre-vingt-dix-huit": 98,
    "quatre-vingt-dix-neuf": 99,
    "cent": 100,
    "cents": 100,
    "mille": 1_000,
    "millier": 1_000,
    "milliers": 1_000,
    "million": 1_000_000, 
    "millions":1_000_000,
    "milliard": 1_000_000_000,
    "milliards": 1_000_000_000,
    # EN
    "zero": 0,
    "one": 1,
    "two": 2,
    "three": 3,
    "four": 4,
    "five": 5,
    "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,
    "hundreds": 100,
    "thousand": 1_000,
    "thousands": 1_000,
    "billion": 1_000_000_000,
    "billions": 1_000_000_000,
    # ES
    "cero": 0,
    "uno": 1,
    "dos": 2,
    "tres": 3,
    "cuatro": 4,
    "cinco": 5,
    "seis": 6,
    "siete": 7,
    "ocho": 8,
    "nueve": 9,
    "diez": 10,
    "once": 11,
    "doce": 12,
    "trece": 13,
    "catorce": 14,
    "quince": 15,
    "dieciséis": 16,
    "diecisiete": 17,
    "dieciocho": 18,
    "diecinueve": 19,
    "veinte": 20,
    "veintiuno": 21,
    "veintidós": 22,
    "veintitrés": 23,
    "veinticuatro": 24,
    "veinticinco": 25,
    "veintiséis": 26,
    "veintisiete": 27,
    "veintiocho": 28,
    "veintinueve": 29,
    "treinta": 30,
    "treinta y uno": 31,
    "treinta y dos": 32,
    "treinta y tres": 33,
    "treinta y cuatro": 34,
    "treinta y cinco": 35,
    "treinta y seis": 36,
    "treinta y siete": 37,
    "treinta y ocho": 38,
    "treinta y nueve": 39,
    "cuarenta": 40,
    "cuarenta y uno": 41,
    "cuarenta y dos": 42,
    "cuarenta y tres": 43,
    "cuarenta y cuatro": 44,
    "cuarenta y cinco": 45,
    "cuarenta y seis": 46,
    "cuarenta y siete": 47,
    "cuarenta y ocho": 48,
    "cuarenta y nueve": 49,
    "cincuenta": 50,
    "cincuenta y uno": 51,
    "cincuenta y dos": 52,
    "cincuenta y tres": 53,
    "cincuenta y cuatro": 54,
    "cincuenta y cinco": 55,
    "cincuenta y seis": 56,
    "cincuenta y siete": 57,
    "cincuenta y ocho": 58,
    "cincuenta y nueve": 59,
    "sesenta": 60,
    "sesenta y uno": 61,
    "sesenta y dos": 62,
    "sesenta y tres": 63,
    "sesenta y cuatro": 64,
    "sesenta y cinco": 65,
    "sesenta y seis": 66,
    "sesenta y siete": 67,
    "sesenta y ocho": 68,
    "sesenta y nueve": 69,
    "setenta": 70,
    "setenta y uno": 71,
    "setenta y dos": 72,
    "setenta y tres": 73,
    "setenta y cuatro": 74,
    "setenta y cinco": 75,
    "setenta y seis": 76,
    "setenta y siete": 77,
    "setenta y ocho": 78,
    "setenta y nueve": 79,
    "ochenta": 80,
    "ochenta y uno": 81,
    "ochenta y dos": 82,
    "ochenta y tres": 83,
    "ochenta y cuatro": 84,
    "ochenta y cinco": 85,
    "ochenta y seis": 86,
    "ochenta y siete": 87,
    "ochenta y ocho": 88,
    "ochenta y nueve": 89,
    "noventa": 90,
    "noventa y uno": 91,
    "noventa y dos": 92,
    "noventa y tres": 93,
    "noventa y cuatro": 94,
    "noventa y cinco": 95,
    "noventa y seis": 96,
    "noventa y siete": 97,
    "noventa y ocho": 98,
    "noventa y nueve": 99,
    "cien": 100,
    "ciento": 100,
    "cientos": 100,
    "docientos": 200,
    "doscientos": 200,
    "trescientos": 300,
    "cuatrocientos": 400,
    "quinientos": 500,
    "seiscientos": 600,
    "setecientos": 700,
    "ochocientos": 800,
    "novecientos": 900,
    "mil": 1_000,
    "miles": 1_000,
    "millón": 1_000_000,
    "millones": 1_000_000,
    "mil-millones": 1_000_000_000,
    "millardo": 1_000_000_000,
    "millardos": 1_000_000_000,
    "billón": 1_000_000_000,
    "billones": 1_000_000_000,
}

UNIT = [
    # FR
    'cent', 
    'cents', 
    'mille',
    'millier',
    'milliers',
    'million',
    'millions',
    'milliard',
    'milliards',
    # EN
    'hundred',
    'hundreds',
    'thousand',
    'thousands',
    'billion',
    'billions',
    # ES
    'cien', 
    'cientos', 
    'mil',
    'miles',
    'millón',
    'millones',
    'mil-millones',
    'millardo',
    'millardos',
    'billón',
    'billones'
]


def convert(sentence, demical_part=False):
    '''
    Converts a sentence containing a number written in words into a number.

    Args:
        - sentence (str) : a string that includes numbers written in letters

    Return:
        - Int or Float
    
    FR:
    >>> convert("un")
    1
    >>> convert("dix")
    10
    >>> convert("cent")
    100
    >>> convert("mille")
    1000
    >>> convert("trois mille")
    3000
    >>> convert("dix mille deux cent quarante-sept")
    10247
    >>> convert("un million cinq cent mille")
    1500000
    >>> convert("deux millions cent trente-quatre mille")
    2134000
    >>> convert("quatre milliards deux cent cinquante-trois millions huit cent vingt mille neuf cents")
    4253820900
    >>> convert("dix-sept milliards six cent quatre-vingt-neuf millions cinq cent quarante-sept mille deux cent trois")
    17689547203
    >>> convert("dix-sept milliards soixante et un")
    17000000061
    >>> convert("quatre virgule cinq")
    4.5
    >>> convert("trois cents virgule soixante-quinze")
    300.75
    >>> convert("un million cinq virgule vingt-cinq")
    1000005.25
    >>> convert("zéro virgule un")
    0.1
    >>> convert("soixante-dix-sept virgule quatre-vingt-huit")
    77.88

    EN:
    >>> convert("one")
    1
    >>> convert("ten")
    10
    >>> convert("hundred")
    100
    >>> convert("thousand")
    1000
    >>> convert("three thousand")
    3000
    >>> convert("ten thousand two hundred forty-seven")
    10247
    >>> convert("one million five hundred thousand")
    1500000
    >>> convert("two million one hundred thirty-four thousand")
    2134000
    >>> convert("four billion two hundred fifty-three million eight hundred twenty thousand nine hundred")
    4253820900
    >>> convert("seventeen billion six hundred eighty-nine million five hundred forty-seven thousand two hundred three")
    17689547203
    >>> convert("seventeen billion sixty-one")
    17000000061
    >>> convert("four point five")
    4.5
    >>> convert("three hundred point seventy-five")
    300.75
    >>> convert("one million five point twenty-five")
    1000005.25
    >>> convert("zero point one")
    0.1
    >>> convert("seventy-seven point eighty-eight")
    77.88

    ES:
    >>> convert("uno")
    1
    >>> convert("diez")
    10
    >>> convert("cien")
    100
    >>> convert("mil")
    1000
    >>> convert("tres mil")
    3000
    >>> convert("diez mil doscientos cuarenta y siete")
    10247
    >>> convert("un millón quinientos mil")
    1500000
    >>> convert("dos millones ciento treinta y cuatro mil")
    2134000
    >>> convert("cuatro mil millones doscientos cincuenta y tres millones ochocientos veinte mil novecientos")
    4253820900
    >>> convert("diecisiete mil millones seiscientos ochenta y nueve millones quinientos cuarenta y siete mil doscientos tres")
    17689547203
    >>> convert("diecisiete mil millones sesenta y uno")
    17000000061
    >>> convert("cuatro punto cinco")
    4.5
    >>> convert("trescientos punto setenta y cinco")
    300.75
    >>> convert("un millón cinco punto veinticinco")
    1000005.25
    >>> convert("cero punto uno")
    0.1
    >>> convert("setenta y siete punto ochenta y ocho")
    77.88
    '''
    # Check Args
    if not demical_part:
        sentence = sentence.replace('mil millones', 'mil-millones')
        lst_words = sentence.split(" ")
        int_decimal_number = 0

        # Detect Float Number
        for i in range(len(lst_words)):
            if (isinstance(lst_words[i], str)): # Check if String
                if lst_words[i] in ['virgule', 'point', 'punto']:
                    int_decimal_number = convert(lst_words[i:], True)
                    lst_words = lst_words[0 : i]
                    break
    else:
        lst_words = sentence

    int_result_number = 0

    # Convert and Detect Units
    lst_units_index = []
    for i in range(len(lst_words)):
        if lst_words[i] in UNIT: # Keep Unit Index
            lst_units_index.append(i)
        if lst_words[i] in NUM: # Convert word
            lst_words[i] = NUM[lst_words[i]]

    # Remove Strings
    for i in range(len(lst_words) - 1, -1, -1):
        if (isinstance(lst_words[i], str)):
            del lst_words[i]
            for j in range(len(lst_units_index)):
                if lst_units_index[j] > i:
                    lst_units_index[j] -= 1
    
    # Cut by Unit
    lst_packet = []
    if len(lst_units_index) > 1:
        int_tmp_index = 0
        for i in range(1, len(lst_units_index)):
            if (lst_words[lst_units_index[i]] < lst_words[lst_units_index[i - 1]]):
                lst_packet.append(lst_words[int_tmp_index : lst_units_index[i - 1] + 1])
                int_tmp_index = lst_units_index[i - 1] + 1
        lst_packet.append(lst_words[int_tmp_index :])
    else:
        lst_packet = [lst_words.copy()]

    # Inter-packet operation
    lst_num = []
    for lst in lst_packet:
        if len(lst) > 1:
            int_tmp_result = 0
            for i in range(len(lst)):
                if lst[i] in [100, 1_000, 1_000_000, 1_000_000_000] and i != 0:
                    int_tmp_result *= lst[i]
                else:
                    int_tmp_result += lst[i]
            lst_num.append(int_tmp_result) 
        else:
            lst_num.append(lst[0]) 
    
    # Grouping packages
    for num in lst_num:
        int_result_number += num
    
    # Return
    if (not demical_part) and (int_decimal_number != 0):
        return int_result_number + (int_decimal_number / (10 ** len(str(int_decimal_number))))
    else:
        return int_result_number

if __name__ == '__main__':
    import doctest
    doctest.testmod()
