import re

def read_structures(lines, structure_tag):
    """
    Returns an iterator over structures in a vertical file. The contents
    of each structure are returned as a list of lines. The first line 
    always contains the opening tag and the last line the closing tags.
    """
    structure = []
    for line in lines:
        if line.startswith('<%s>' % structure_tag) or \
                line.startswith('<%s ' % structure_tag):
            if structure:
                yield structure
            # new structure
            structure = [line]
        else:
            if structure: # if in an open structure
                # read structure
                structure.append(line)
    # last structure
    if structure:
        yield structure

def read_big_structures(fp, structure_tag, buffer_size=10000000):
    """
    Returns an iterator over structures in a vertical file, represented as
    a file-like object. The contents of each structure are returned as string.
    For large structures, this method is much more efficient than 
    read_structures.
    """
    # TODO: take ending tags into account
    structure_start_re = re.compile('^<%s[ >]' % structure_tag, re.M)
    buffer = ""
    while True:
        new_data = fp.read(buffer_size)
        if not new_data:
            break
        buffer += new_data
        starting_positions = [m.start() for m in structure_start_re.finditer(buffer)]
        if starting_positions == []:
            continue
        for i in range(len(starting_positions) - 1):
            start = starting_positions[i]
            end = starting_positions[i + 1]
            yield buffer[start:end]
        buffer = buffer[starting_positions[-1]:]
    if buffer != "":
        yield buffer

def get_attributes(tag):
    """
    Returns a dict of attributes and values of a SGML-like structure
    at the beginning of the string.
    """
    m = re.match('^<\S+\s*([^>]*)>', tag)
    if not m:
        return {}
    attributes = m.group(1)
    return dict(re.findall('(\w+)="([^"]+)"', attributes))
