Вот попытка недетерминированно (читайте: исчерпывающе) решить проблему поиска, где даты в токенизированном тексте. Он перечисляет все способы разделения предложения (как список токенов) с размером раздела от minps
до maxps
.
Каждое разбиение выполняется в синтаксический анализатор, который выводит список разобранных дат и диапазон токенов, где он был разобран.
Результат каждого парсера оценивается с суммой значений токенов в квадрате (поэтому, чтобы предпочесть дату, обработанную из 4 жетонов, а не 2 даты, разобранных по 2 жетонам).
Наконец, он находит и выводит синтаксис с лучшим результатом.
Три строительные блоки алгоритма:
from dateutil.parser import parse as parsedate
def partition(lst, minps, maxps, i=0):
if lst == []:
yield []
else:
try:
for l in range(minps, maxps+1):
if l > len(lst): continue
for z in partition(lst[l:], minps, maxps, i+l):
yield [(i, lst[:l])] + z
except:
pass
def parsedates(p):
for x in p:
i, pi = x
try:
d = parsedate(' '.join(pi))
# output: (startIndex, endIndex, parsedDate)
if d: yield i, i+len(pi), d
except: pass
def score(p):
score = 0
for pi in p:
score += (pi[1]-pi[0])**2
return score
Нахождение разбора с лучшим счетом:
def bestparse(toks, maxps=3):
bestscore = 0
bestparse = None
for ps in partition(toks, 1, maxps):
l = list(parsedates(ps))
s = score(l)
if s > bestscore:
bestscore = s
bestparse = l
return bestparse
Некоторые тесты:
l=['bla', 'bla', 'bla', '12', 'Jan', '14', 'bla', 'bla', 'bla', '01/04/15', 'bla', 'bla']
for bpi in bestparse(l):
print('found date %s at tokens %s' % (bpi[2], ','.join(map(str, range(*bpi[:2])))))
найдено Дата 2014-01 -12 00:00:00 в токенах 3,4,5
найдено дата 2015-01-04 00:00:00 знамений 9
l=['Fred', 'was', 'born', 'on', '23/1/99', 'at', '23:30']
for bpi in bestparse(l, 5):
print('found date %s at tokens %s' % (bpi[2], ','.join(map(str, range(*bpi[:2])))))
найдено дата 1999-01-23 23:30:00 на лексемы 3,4,5,6
Опасайтесь, что это может быть очень дорогостоящим, поэтому вы можете запускать его на отдельных коротких фразах, а не на весь документ. Вы даже можете разделить длинные фразы на куски.
Еще один момент для улучшения - функция разбиения. Если у вас есть предварительная информация, например, сколько дат может быть не более одного предложения, количество способов ее разделения может быть значительно уменьшено.
Возможный дубликат [парсер времени на естественном языке] (http://stackoverflow.com/questions/11340963/natural-language-time-parser) – danihp
@ danihp Я так не думаю. Я ищу парсер, который извлекает даты, внедренные в произвольные строки, вместо того, чтобы анализировать строку даты в объекте. – Kar
@Kar год они будут как 14, а не 2014 во всех случаях? – Ajay