import re


def parse_formula(formula):
    """
    Parses the Hill formulae. Does not need spaces as separators.
    Works also for partial occupancies and for chemical groups enclosed in round/square/curly brackets.
    Elements are counted and a dictionary is returned.
    e.g.  'C[NH2]3NO3'  -->  {'C': 1, 'N': 4, 'H': 6, 'O': 3}
    """

    def chemcount_str_to_number(string):
        if not string:
            quantity = 1
        else:
            quantity = float(string)
            if quantity.is_integer():
                quantity = int(quantity)
        return quantity

    contents = {}

    # split blocks with parentheses
    for block in re.split(r'(\([^\)]*\)[^A-Z\(\[\{]*|\[[^\]]*\][^A-Z\(\[\{]*|\{[^\}]*\}[^A-Z\(\[\{]*)', formula):
        if not block:  # block is void
            continue

        # get molecular formula (within parentheses) & count
        group = re.search(r'[\{\[\(](.+)[\}\]\)]([\.\d]*)', block)
        if group is None:  # block does not contain parentheses
            molformula = block
            molcount = 1
        else:
            molformula = group.group(1)
            molcount = chemcount_str_to_number(group.group(2))

        for part in re.findall(r'[A-Z][^A-Z\s]*', molformula.replace(' ', '')):  # split at uppercase letters
            match = re.match(r'(\D+)([\.\d]+)?', part)  # separates element and count

            if match is None:
                continue

            species = match.group(1)
            quantity = chemcount_str_to_number(match.group(2)) * molcount
            contents[species] = contents.get(species, 0) + quantity
    return contents