from __future__ import unicode_literals
import os
from os import path
import re
def split(text):
"""Split an annotation file by sentence. Each sentence's annotation should
be a single string."""
return text.strip().split('\n')[1:-1]
def parse(string, strip_bad_periods=False):
"""Given a sentence's annotation string, return a list of word strings,
and a list of named entities, where each entity is a (start, end, label)
triple."""
tokens = []
tags = []
open_tag = None
# Arbitrary corrections to promote alignment, and ensure that entities
# begin at a space. This allows us to treat entities as tokens, making it
# easier to return the list of entities.
string = string.replace('... .', '...')
string = string.replace('U.S. .', 'U.S.')
string = string.replace('Co. .', 'Co.')
string = string.replace('U.S. .', 'U.S.')
string = string.replace('- - Paula Zahn', 'Paula Zahn')
string = string.replace('little drain', 'little drain')
for substr in string.strip().split():
substr = _fix_inner_entities(substr)
tokens.append(_get_text(substr))
try:
tag, open_tag = _get_tag(substr, open_tag)
except:
raise
tags.append(tag)
return tokens, tags
tag_re = re.compile(r'')
def _fix_inner_entities(substr):
tags = tag_re.findall(substr)
if '', '') + ''
if tags:
substr = tag_re.sub('', substr)
return tags[0] + substr
else:
return substr
def _get_tag(substr, tag):
if substr.startswith('<'):
tag = substr.split('"')[1]
if substr.endswith('>'):
return 'U-' + tag, None
else:
return 'B-%s' % tag, tag
elif substr.endswith('>'):
return 'L-' + tag, None
elif tag is not None:
return 'I-' + tag, tag
else:
return 'O', None
def _get_text(substr):
if substr.startswith('<'):
substr = substr.split('>', 1)[1]
if substr.endswith('>'):
substr = substr.split('<')[0]
return reform_string(substr)
def tags_to_entities(tags):
entities = []
start = None
for i, tag in enumerate(tags):
if tag.startswith('O'):
# TODO: We shouldn't be getting these malformed inputs. Fix this.
if start is not None:
start = None
continue
elif tag == '-':
continue
elif tag.startswith('I'):
assert start is not None, tags[:i]
continue
if tag.startswith('U'):
entities.append((tag[2:], i, i))
elif tag.startswith('B'):
start = i
elif tag.startswith('L'):
entities.append((tag[2:], start, i))
start = None
else:
raise Exception(tag)
return entities
def reform_string(tok):
tok = tok.replace("``", '"')
tok = tok.replace("`", "'")
tok = tok.replace("''", '"')
tok = tok.replace('\\', '')
tok = tok.replace('-LCB-', '{')
tok = tok.replace('-RCB-', '}')
tok = tok.replace('-RRB-', ')')
tok = tok.replace('-LRB-', '(')
tok = tok.replace("'T-", "'T")
tok = tok.replace('-AMP-', '&')
return tok