pympi/Elan.py
def eaf_from_chat(file_path, codec='ascii', extension='wav'):
    """Reads a .cha file and converts it to an elan object. The functions tries
    to mimic the CHAT2ELAN program that comes with the CLAN package as close as
    possible. This function however converts to the latest ELAN file format
    since the library is designed for it. All CHAT headers will be added as
    Properties in the object and the headers that have a similar field in an
    Eaf file will be added there too. The file description of chat files can be
    found `here <http://childes.psy.cmu.edu/manuals/CHAT.pdf>`_.

    :param str file_path: The file path of the .cha file.
    :param str codec: The codec, if the @UTF8 header is present it will choose
        utf-8, default is ascii. Older CHAT files don't have their encoding
        embedded in a header so you will probably need to choose some obscure
        ISO charset then.
    :param str extension: The extension of the media file.
    :throws StopIteration: If the file doesn't contain a @End header, thus
        inferring the file is broken.
    """
    eafob = Eaf()
    eafob.add_linguistic_type('parent')
    eafob.add_linguistic_type(
        'child', constraints='Symbolic_Association', timealignable=False)
    participantsdb = {}
    last_annotation = None
    with open(file_path, 'r') as chatin:
        while True:
            line = chatin.readline().strip().decode(codec)
            if line == '@UTF8':  # Codec marker
                codec = 'utf8'
                continue
            elif line == '@End':  # End of file marker
                break
            elif line.startswith('@') and line != '@Begin':  # Header marker
                key, value = line.split(':\t')
                eafob.add_property('{}:\t'.format(key), value)
                if key == '@Languages':
                    for language in value.split(','):
                        eafob.add_language(language)
                elif key == '@Participants':
                    for participant in value.split(','):
                        splits = participant.strip().split(' ')
                        splits = map(lambda x: x.replace('_', ' '), splits)
                        if len(splits) == 2:
                            participantsdb[splits[0]] = (None, splits[1])
                        elif len(splits) == 3:
                            participantsdb[splits[0]] = (splits[1], splits[2])
                elif key == '@ID':
                    ids = map(lambda x: x.replace('_', ''), value.split('|'))
                    eafob.add_tier(ids[2], part=participantsdb[ids[2]][0],
                                   language=ids[0])
                elif key == '@Media':
                    media = value.split(',')
                    eafob.add_linked_file(
                        'file://{}.{}'.format(media[0], extension))
                elif key == '@Transcriber:':
                    for tier in eafob.get_tier_names():
                        eafob.tiers[tier][2]['ANNOTATOR'] = value
            elif line.startswith('*'):  # Main tier marker
                while len(line.split('\x15')) != 3:
                    line += chatin.readline().decode(codec).strip()
                for participant in participantsdb.keys():
                    if line.startswith('*{}:'.format(participant)):
                        splits = ''.join(line.split(':')[1:]).strip()
                        utt, time, _ = splits.split('\x15')
                        time = map(int, time.split('_'))
                        last_annotation = (participant, time[0], time[1], utt)
                        eafob.add_annotation(*last_annotation)
            elif line.startswith('%'):  # Dependant tier marker
                splits = line.split(':')
                name = '{}_{}'.format(last_annotation[0], splits[0][1:])
                if name not in eafob.get_tier_names():
                    eafob.add_tier(name, 'child', last_annotation[0])
                eafob.add_ref_annotation(
                    name, last_annotation[0], sum(last_annotation[1:3])/2,
                    ''.join(splits[1:]).strip())
    return eafob
def eaf_from_chat(file_path, codec='ascii', extension='wav'):
    """Reads a .cha file and converts it to an elan object. The functions tries
    to mimic the CHAT2ELAN program that comes with the CLAN package as close as
    possible. This function however converts to the latest ELAN file format
    since the library is designed for it. All CHAT headers will be added as
    Properties in the object and the headers that have a similar field in an
    Eaf file will be added there too. The file description of chat files can be
    found `here <http://childes.psy.cmu.edu/manuals/CHAT.pdf>`_.

    :param str file_path: The file path of the .cha file.
    :param str codec: The codec, if the @UTF8 header is present it will choose
        utf-8, default is ascii. Older CHAT files don't have their encoding
        embedded in a header so you will probably need to choose some obscure
        ISO charset then.
    :param str extension: The extension of the media file.
    :throws StopIteration: If the file doesn't contain a @End header, thus
        inferring the file is broken.
    """
    eafob = Eaf()
    eafob.add_linguistic_type('parent')
    eafob.add_linguistic_type(
        'child', constraints='Symbolic_Association', timealignable=False)
    participantsdb = {}
    last_annotation = None
    with open(file_path, 'r') as chatin:
        while True:
            line = chatin.readline().strip().decode(codec)
            if line == '@UTF8':  # Codec marker
                codec = 'utf8'
                continue
            elif line == '@End':  # End of file marker
                break
            elif line.startswith('@') and line != '@Begin':  # Header marker
                key, value = line.split(':\t')
                eafob.add_property('{}:\t'.format(key), value)
                if key == '@Languages':
                    for language in value.split(','):
                        eafob.add_language(language)
                elif key == '@Participants':
                    for participant in value.split(','):
                        splits = participant.strip().split(' ')
                        splits = map(lambda x: x.replace('_', ' '), splits)
                        if len(splits) == 2:
                            participantsdb[splits[0]] = (None, splits[1])
                        elif len(splits) == 3:
                            participantsdb[splits[0]] = (splits[1], splits[2])
                elif key == '@ID':
                    ids = map(lambda x: x.replace('_', ''), value.split('|'))
                    eafob.add_tier(ids[2], part=participantsdb[ids[2]][0],
                                   language=ids[0])
                elif key == '@Media':
                    media = value.split(',')
                    eafob.add_linked_file(
                        'file://{}.{}'.format(media[0], extension))
                elif key == '@Transcriber:':
                    for tier in eafob.get_tier_names():
                        eafob.tiers[tier][2]['ANNOTATOR'] = value
            elif line.startswith('*'):  # Main tier marker
                while len(line.split('\x15')) != 3:
                    line += chatin.readline().decode(codec).strip()
                for participant in participantsdb.keys():
                    if line.startswith('*{}:'.format(participant)):
                        splits = ''.join(line.split(':')[1:]).strip()
                        utt, time, _ = splits.split('\x15')
                        time = map(int, time.split('_'))
                        last_annotation = (participant, time[0], time[1], utt)
                        eafob.add_annotation(*last_annotation)
            elif line.startswith('%'):  # Dependant tier marker
                splits = line.split(':')
                name = '{}_{}'.format(last_annotation[0], splits[0][1:])
                if name not in eafob.get_tier_names():
                    eafob.add_tier(name, 'child', last_annotation[0])
                eafob.add_ref_annotation(
                    name, last_annotation[0], sum(last_annotation[1:3])/2,
                    ''.join(splits[1:]).strip())
    return eafob
Reads a .cha file and converts it to an elan object. The functions tries
    to mimic the CHAT2ELAN program that comes with the CLAN package as close as
    possible. This function however converts to the latest ELAN file format
    since the library is designed for it. All CHAT headers will be added as
    Properties in the object and the headers that have a similar field in an
    Eaf file will be added there too. The file description of chat files can be
    found `here <http://childes.psy.cmu.edu/manuals/CHAT.pdf>`_.

    :param str file_path: The file path of the .cha file.
    :param str codec: The codec, if the @UTF8 header is present it will choose
        utf-8, default is ascii. Older CHAT files don't have their encoding
        embedded in a header so you will probably need to choose some obscure
        ISO charset then.
    :param str extension: The extension of the media file.
    :throws StopIteration: If the file doesn't contain a @End header, thus
        inferring the file is broken.