Spaces:
Runtime error
Runtime error
| import re | |
| from dataclasses import dataclass | |
| from enum import Enum | |
| from components.parser.abbreviations.constants import ( | |
| ABBREVIATION_CLEANUP_REPLACEMENTS, | |
| BLACKLIST, | |
| DASH_PATTERN, | |
| MAX_LENGTH, | |
| PREFIX_PARTS_TO_REMOVE, | |
| REMOVING_SUBSTRINGS, | |
| ) | |
| from components.parser.abbreviations.porter import Porter | |
| class AbbreviationType(str, Enum): | |
| ABBREVIATION = 'abbreviation' | |
| SHORTENING = 'shortening' | |
| UNKNOWN = 'unknown' | |
| class Abbreviation: | |
| short_form: str | |
| full_form: str | |
| abbreviation_type: AbbreviationType = AbbreviationType.UNKNOWN | |
| _processed: bool = False | |
| document_id: int | None = None | |
| def process(self) -> 'Abbreviation': | |
| """ | |
| Производит пост-обработку сокращения и полной формы. | |
| - Определяет тип сокращения. | |
| - Удаляет префикс из короткой формы и мусор из полной формы. | |
| - В зависимости от типа сокращения адаптирует его под нужный вид. | |
| """ | |
| if self._processed: | |
| return | |
| self._define_abbreviation_type() | |
| self.short_form = self._remove_prefix(self.short_form) | |
| self.full_form = self._remove_trash(self.full_form) | |
| if self._abbreviation_type == AbbreviationType.SHORTENING: | |
| self._process_shortening() | |
| elif self._abbreviation_type == AbbreviationType.ABBREVIATION: | |
| self._process_abbreviation() | |
| self._processed = True | |
| return self | |
| def apply(self, text: str) -> str: | |
| """ | |
| Применяет аббревиатуру к тексту. | |
| Args: | |
| text (str): Текст для обработки. | |
| Returns: | |
| str: Обработанный текст. | |
| """ | |
| if self._abbreviation_type == AbbreviationType.UNKNOWN: | |
| return text | |
| if self._abbreviation_type == AbbreviationType.SHORTENING: | |
| return self._apply_shortening(text) | |
| elif self._abbreviation_type == AbbreviationType.ABBREVIATION: | |
| return self._apply_abbreviation(text) | |
| def _apply_shortening(self, text: str) -> str: | |
| """ | |
| Применяет сокращение к тексту. | |
| Args: | |
| text (str): Текст для обработки. | |
| Returns: | |
| str: Обработанный текст. | |
| """ | |
| matches = list(re.finditer(self.short_form, text)) | |
| for i in range(len(matches) - 1, 1, -1): | |
| m = matches[i] | |
| pos1 = m.start() | |
| m2 = re.match(r'[A-Za-zА-Яа-я]+', text[pos1:]) | |
| pos2 = pos1 + m2.end() | |
| explanation = self.full_form | |
| m3 = re.match(r'[A-Za-zА-Яа-я]+', explanation) | |
| explanation = explanation[m3.end() :] | |
| text = text[:pos2] + explanation + text[pos2:] | |
| return text | |
| def _apply_abbreviation(self, text: str) -> str: | |
| """ | |
| Применяет аббревиатуру к тексту. | |
| Args: | |
| text (str): Текст для обработки. | |
| Returns: | |
| str: Обработанный текст. | |
| """ | |
| matches = list(re.finditer(self.short_form, text)) | |
| for i in range(len(matches) - 1, 0, -1): | |
| m = matches[i] | |
| text = f'{text[: m.start()]}{self.short_form} ({self.full_form}){text[m.end():]}' | |
| return text | |
| def _define_abbreviation_type(self) -> None: | |
| """ | |
| Определяет тип сокращения. | |
| """ | |
| if self._check_abbreviation(self.full_form): | |
| self._abbreviation_type = AbbreviationType.ABBREVIATION | |
| elif self._check_shortening(self.full_form): | |
| self._abbreviation_type = AbbreviationType.SHORTENING | |
| else: | |
| self._abbreviation_type = AbbreviationType.UNKNOWN | |
| def _process_shortening(self) -> None: | |
| """ | |
| Обрабатывает сокращение. | |
| """ | |
| key = Porter.stem(self.short_form) | |
| pos = self.full_form.lower().rfind(key.lower()) | |
| if pos != -1: | |
| self.full_form = self.full_form[pos:] | |
| self.short_form = key | |
| else: | |
| self.abbreviation_type = AbbreviationType.UNKNOWN | |
| def _process_abbreviation(self) -> None: | |
| """ | |
| Обрабатывает аббревиатуру. | |
| """ | |
| uppercase_letters = re.sub('[a-zа-я, ]', '', self.short_form) | |
| processed_full_form = self._remove_trash_when_abbreviation(self.full_form) | |
| words = processed_full_form.split() | |
| uppercase_letters = uppercase_letters[::-1] | |
| words = words[::-1] | |
| if (len(words) <= len(uppercase_letters)) or ('ОКС НН' not in self.short_form): | |
| self.abbreviation_type = AbbreviationType.UNKNOWN | |
| return | |
| match = self._check_abbreviation_matches_words(uppercase_letters, words) | |
| if match: | |
| self._process_matched_abbreviation(uppercase_letters, words) | |
| else: | |
| self._process_mismatched_abbreviation() | |
| def _process_matched_abbreviation( | |
| self, | |
| uppercase_letters: str, | |
| words: list[str], | |
| ) -> None: | |
| """ | |
| Обрабатывает аббревиатуру, которая совпадает с первыми буквами полной формы. | |
| Args: | |
| uppercase_letters (str): Заглавные буквы из сокращения. | |
| words (list[str]): Список слов, которые составляют аббревиатуру. | |
| """ | |
| pos = len(self.full_form) | |
| for i in range(len(uppercase_letters)): | |
| pos = self.full_form.rfind(words[i], 0, pos) | |
| if pos != -1: | |
| self.full_form = self.full_form[pos:] | |
| else: | |
| self.abbreviation_type = AbbreviationType.UNKNOWN | |
| def _process_mismatched_abbreviation(self) -> None: | |
| """ | |
| Обрабатывает аббревиатуру, которая не совпадает с первыми буквами полной формы. | |
| """ | |
| first_letter = self.short_form[0] | |
| pos = self.full_form.rfind(first_letter) | |
| if pos != -1: | |
| self.full_form = self.full_form[pos:] | |
| first_letter = self.full_form[0] | |
| second_letter = self.full_form[1] | |
| if ( | |
| ('A' < first_letter < 'Z' or 'А' < first_letter < 'Я') | |
| and ('a' < second_letter < 'z' or 'а' < second_letter < 'я') | |
| and len(self.full_form) < MAX_LENGTH | |
| and len(self.full_form) > len(self.short_form) | |
| and self.full_form not in BLACKLIST | |
| and '_' not in self.full_form | |
| ): | |
| return | |
| self.abbreviation_type = AbbreviationType.UNKNOWN | |
| def _check_abbreviation_matches_words( | |
| self, | |
| uppercase_letters: str, | |
| words: list[str], | |
| ) -> bool: | |
| """ | |
| Проверяет, соответствует ли короткая форма аббревиатуре. | |
| Args: | |
| uppercase_letters (str): Заглавные буквы из сокращения. | |
| words (list[str]): Список слов, которые составляют аббревиатуру. | |
| Returns: | |
| bool: True, если аббревиатура соответствует, False в противном случае. | |
| """ | |
| for j in range(len(uppercase_letters)): | |
| c1 = uppercase_letters[j].lower() | |
| c2 = words[j][0].lower() | |
| if c1 != c2: | |
| return False | |
| return True | |
| def _check_abbreviation(cls, full_form: str) -> bool: | |
| """ | |
| Проверяет, является ли строка аббревиатурой. | |
| Args: | |
| full_form (str): Строка для проверки. | |
| Returns: | |
| bool: True, если строка является аббревиатурой, False в противном случае. | |
| """ | |
| s = cls._remove_prefix(full_form) | |
| words = s.split() | |
| for word in words: | |
| n = cls._count_uppercase_letters(word) | |
| if (n <= 1) and (word != 'и'): | |
| return False | |
| return True | |
| def _check_shortening(cls, full_form: str) -> bool: | |
| """ | |
| Проверяет, является ли строка сокращением. | |
| Args: | |
| full_form (str): Строка для проверки. | |
| Returns: | |
| bool: True, если строка является сокращением, False в противном случае. | |
| """ | |
| s = cls._remove_prefix(full_form) | |
| words = s.split() | |
| if len(words) != 1: | |
| return False | |
| word = words[0] | |
| if word[0].isupper() and word[1:].islower() and ('Компания' not in word): | |
| return True | |
| return False | |
| def _remove_prefix(s: str) -> str: | |
| """ | |
| Удаляет из строки префиксы типа "далее - " и "далее – ". | |
| Args: | |
| s (str): Строка для обработки. | |
| Returns: | |
| str: Обработанная строка. | |
| """ | |
| for prefix_part in PREFIX_PARTS_TO_REMOVE: | |
| s = s.replace(prefix_part, '') | |
| return s.strip() | |
| def _remove_trash(s: str) -> str: | |
| """ | |
| Удаляет из строки такие подстроки, как "ПАО", "ОАО", "№", "(". | |
| Args: | |
| s (str): Строка для обработки. | |
| Returns: | |
| str: Обработанная строка. | |
| """ | |
| for substring in REMOVING_SUBSTRINGS: | |
| pos = s.find(substring) | |
| if pos != -1: | |
| s = s[:pos] | |
| return s | |
| def _remove_trash_when_abbreviation(s: str) -> str: | |
| """ | |
| Удаляет из строки такие подстроки, как " и ", " или ", ", ", " ГО". | |
| Заменяет дефисы и тире на пробел. | |
| Это необходимо для того, чтобы правильно сопоставить аббревиатуру с полной формой. | |
| Args: | |
| s (str): Строка для обработки. | |
| Returns: | |
| str: Обработанная строка. | |
| """ | |
| for old, new in ABBREVIATION_CLEANUP_REPLACEMENTS.items(): | |
| s = s.replace(old, new) | |
| s = re.sub(DASH_PATTERN, ' ', s) | |
| return s | |
| def _count_uppercase_letters(s: str) -> int: | |
| """ | |
| Считает количество заглавных букв в строке. | |
| Args: | |
| s (str): Строка для обработки. | |
| Returns: | |
| int: Количество заглавных букв. | |
| """ | |
| return len(re.findall(r'[A-Z,А-Я]', s)) | |