def __init__(self, storage): os.environ['RML'] = AOT_DIR # нужно бинарникам АОТ для работы. Они тупые. self.morpher = Morpher() self.log = LOG_PATH self.log_strings = [] self.rgramtab = Rgramtab() self.sentence_devider = SentenceDevider(AOT_DIR) self.storage = storage
class Analyzer(): ''' Анализатор тональности текста ''' def __init__(self, storage): os.environ['RML'] = AOT_DIR # нужно бинарникам АОТ для работы. Они тупые. self.morpher = Morpher() self.log = LOG_PATH self.log_strings = [] self.rgramtab = Rgramtab() self.sentence_devider = SentenceDevider(AOT_DIR) self.storage = storage def ClearLog(self): self.log_strings = [] def FlushLog(self): output = codecs.open(self.log, 'w', 'utf-8') output.writelines(self.log_strings) output.close() def WriteLog(self, info, msg=None): self.log_strings.append(unicode(info) + u'\n') if msg: self.log_strings.append(unicode(msg) + u'\n\n') def GetSentences(self, text): return self.sentence_devider.enumerate_sentences(unicode(text)) def GetParagraphs(self, text, sentences): result = [] for i,j in sentences: last_index = text.rfind(sentences[i]) begin_index = text.rfind(sentences[i+1]) paragraph_str = text[last_index:begin_index] result.append(paragraph_str) return result def Analyze(self, text): # очищаем лог self.ClearLog() self.WriteLog(u"Исходный текст:", text) sentences = self.GetSentences(text) render_text = [] text_tone = 0 total_word_count = 0 for s in sentences: render_sentence, sentence_tone, word_count = self.AnalyzeSentence(s) total_word_count += word_count text_tone += sentence_tone render_text.append(render_sentence) html = self.RenderTextToHtml(render_text) # записываем изменения в лог-файл #self.WriteLog(u"Полученный текст:", html) text_tone /= total_word_count html += self.GetTotalRenderText(text_tone) self.FlushLog() return html, text_tone def GetTotalRenderText(self, text_tone): if text_tone > 0: result = u"<br><br><good>Текст окрашен положительно. Значение тональности: " + unicode(text_tone) + u"</good>" else: result = u"<br><br><bad>Текст окрашен отрицательно. Значение тональности: " + unicode(text_tone) + u"</bad>" return result def RenderTextToHtml(self, render_text): result = u'' for sentence in render_text: for word in sentence: if self.CheckToBePunctuationMark(word): result = result[:len(result)-1] result = result + word + u' ' return result def CheckToBePunctuationMark(self, word): result = False if re.match("[.,!?:]", word): result = True return result def AnalyzeSentence(self, sentence): ''' Анализ предложения на тональность ''' self.WriteLog(u"==============================================\nТекущее предложение:", sentence) words = unicode(sentence).split(' ') word_count = len(words) render_sentence = [] # список юникодных слов self.WriteLog(u"===== Первичная расстановка тональностей =====") tonal_words = self.GetPrimaryTonalWeights(words) # tonal_words содержит (слово, тональность) # анализируем слова с тональностью <>0 # TODO: работа с тональностями! коррекция тональности self.WriteLog(u"===== Расстановка тональностей внутри предложения =====") tonal_words = self.Reanalyze(tonal_words) # печать sentence_tone = 0 for w in tonal_words: if w[3] == 0: sentence_tone += w[1] render_word = self.GetRenderWord(w) render_sentence.append(render_word) return render_sentence, sentence_tone, word_count def Reanalyze(self, tonal_words): ''' Реализация основного алгоритма ''' i = len(tonal_words) - 1 while i > 0: #for i in range(len(tonal_words), 0, -1): # ищем слово из словаря тональностей if tonal_words[i][3] == None or tonal_words[i][3] > 0: i-=1 continue self.WriteLog(u"Текущее эмоционально окрашенное слово: " + tonal_words[i][0]) # нашли эмоционально окрашенное слово # пойдем вперед и посмотрим на слова correcting_value = 0 need_to_invert = False k = 0 # сколько обработали слов for j in range(i-1, -1, -1): if not tonal_words[j][3]: # если слово из обычного словаря break k += 1 # находится ли в словаре повышения тональности? if tonal_words[j][3] == 1: correcting_value += tonal_words[j][1] if not tonal_words[j][1]: # надо инвертировать need_to_invert = not need_to_invert self.WriteLog(u"-" + unicode(k) + u": слово \'" + tonal_words[j][0] + u"\' инверитрует тональность!") else: self.WriteLog(u"-" + unicode(k) + u": слово \'" + tonal_words[j][0] + u"\' изменяет тональность на " + unicode(tonal_words[j][1])) result_tone_value = tonal_words[i][1] + correcting_value if need_to_invert: result_tone_value *= -1 # присвоим всему обороту полученную окраску for j in range(i-k, i): tonal_words[j] = tonal_words[j][0], tonal_words[j][1], tonal_words[j][2], 3 # словарь = 3 - для того чтобы отличить слова повышения tonal_words[i] = tonal_words[i][0], result_tone_value, tonal_words[i][2], tonal_words[i][3] if k: i -= k else: i -= 1 return tonal_words def GetRenderWord(self, tonal_word): ''' ''' unicode_word, tone_value, norm_form, dict_numb = tonal_word render_word = self.GetWordToRender(unicode_word, tone_value, dict_numb) return render_word def GetPrimaryTonalWeights(self, unicode_words): ''' Получить словарь слово, тональность ''' result = [] for w in unicode_words: result.append(self.AnalyzeWord(w)) return result def AnalyzeWord(self, unicode_word): ''' Анализ слова. Возвращаем (слово(норм), тональность). Если нет норм формы то (слово(юникод), 0) ''' # проверка на знак пунктуации if re.match("[-\n.,!?:]", unicode_word): return unicode_word, 0, None, None # проверка на суффиксы и тд pre_tone_value = self.AnalyzeWordSuffix(unicode_word) result = None word_normform = self.GetWordNormForm(unicode_word) # структуру WordWrapper можно анализировать на часть речи и тд if word_normform: search_word = word_normform.GetNormForm() else: #self.WriteLog(u"Слово не имеет нормальной формы: " + unicode_word, "") search_word = unicode_word #if word_normform: tone_value, dict_numb = self.GetWordToneValue(unicode_word, search_word) if not tone_value: tone_value += pre_tone_value result = (unicode_word, tone_value, word_normform, dict_numb) self.WriteLog(u"Слово: " + unicode_word + u';\nНормальная форма: ' + unicode(word_normform) + u";\nСловарь: " + unicode(dict_numb) + u';\nТональность: '+ unicode(tone_value) + u";\n") #else: # self.WriteLog(u"Слово не имеет нормальной формы: ", unicode_word) # result = (unicode_word, pre_tone_value, None, None) return result def AnalyzeWordSuffix(self, unicode_word): ''' Анализ слова на наличие суффиксов -еньк, -оньк, ''' pre_tone_value = 0 suffix = [u"еньк", u"оньк", u"чик", u"ошк", u"ушк", u"ышк", u"юшк"] for s in suffix: if re.search(s, unicode_word, re.IGNORECASE): pre_tone_value += 0.1 return pre_tone_value def SelectMostPossibleWord(self, word_forms): ''' Выбираем из форм слова наиболее возможную ''' result = None max_weight = -1 # все значения положительные for w in word_forms: cur_weight = w.GetWordWeight() if w.GetWordWeight() > max_weight: max_weight = cur_weight result = w return result def GetWordToRender(self, word, tone_value, dict_numb): ''' Получение слова для отображения ''' if not tone_value or dict_numb == 1: # если не установлено значение тональности либо слово из повышающего словаря return word tag = u'' if dict_numb == 3: tag = u"changing" #word = u"<changing>" + word + u"(" + unicode(tone_value) + u")" + u"</changing>" else: if tone_value > 0: #word = u'<good>' + word + u"(" + unicode(tone_value) + u")" + u'</good>' tag = u"good" else: #word = u'<bad>' + word + u"(" + unicode(tone_value) + u")" + u'</bad>' tag = u"bad" word = u"<" + tag + u">" + word + u"(" + unicode(tone_value) + u")" + u"</" + tag + u">" return word def GetWordNormForm(self, unicode_word): word_forms = self.morpher.GetWordForms(unicode_word) result_word = self.SelectMostPossibleWord(word_forms) return result_word def GetWordToneValue(self, unicode_word, norm_form): ''' Проверка на наличие слова в тональном словаре. Возвращение значения тональности в случае успеха ''' result, dict_numb = self.storage.GetWordToneValue(unicode_word, norm_form.lower()) if result == None: result = 0 dict_numb = None return result, dict_numb