Пример #1
0
class Token:
    """ Базовый класс для всех токенов """
    def __init__(self, kit_: 'AnalysisKit', begin: int, end: int) -> None:
        self.kit = None
        self.begin_char = 0
        self.end_char = 0
        self.tag = None
        self._m_previous = None
        self._m_next = None
        self.__m_morph = None
        self.chars = None
        self.__m_attrs = 0
        self.kit = kit_
        self.begin_char = begin
        self.end_char = end

    @property
    def length_char(self) -> int:
        """ Длина в исходных символах """
        return (self.end_char - self.begin_char) + 1

    @property
    def previous(self) -> 'Token':
        """ Предыдущий токен """
        return self._m_previous

    @previous.setter
    def previous(self, value) -> 'Token':
        self._m_previous = value
        if (value is not None):
            value._m_next = self
        self.__m_attrs = (0)
        return value

    @property
    def next0_(self) -> 'Token':
        """ Следующий токен """
        return self._m_next

    @next0_.setter
    def next0_(self, value) -> 'Token':
        self._m_next = value
        if (value is not None):
            value._m_previous = self
        self.__m_attrs = (0)
        return value

    @property
    def morph(self) -> 'MorphCollection':
        """ Морфологическая информация """
        if (self.__m_morph is None):
            self.__m_morph = MorphCollection()
        return self.__m_morph

    @morph.setter
    def morph(self, value) -> 'MorphCollection':
        self.__m_morph = value
        return value

    def __str__(self) -> str:
        return self.kit.sofa.text[self.begin_char:self.begin_char +
                                  (self.end_char + 1) - self.begin_char]

    def __getAttr(self, i: int) -> bool:
        if ((((self.__m_attrs) & 1)) == 0):
            self.__m_attrs = (1)
            if (self._m_previous is None):
                self._setAttr(1, True)
                self._setAttr(3, True)
            else:
                j = self._m_previous.end_char + 1
                while j < self.begin_char:
                    ch = self.kit.sofa.text[j]
                    if (Utils.isWhitespace((ch))):
                        self._setAttr(1, True)
                        if ((ord(ch)) == 0xD or (ord(ch)) == 0xA
                                or ch == '\f'):
                            self._setAttr(3, True)
                    j += 1
            if (self._m_next is None):
                self._setAttr(2, True)
                self._setAttr(4, True)
            else:
                j = self.end_char + 1
                while j < self._m_next.begin_char:
                    ch = self.kit.sofa.text[j]
                    if (Utils.isWhitespace(ch)):
                        self._setAttr(2, True)
                        if ((ord(ch)) == 0xD or (ord(ch)) == 0xA
                                or ch == '\f'):
                            self._setAttr(4, True)
                    j += 1
        return (((((self.__m_attrs) >> i)) & 1)) != 0

    def _setAttr(self, i: int, val: bool) -> None:
        if (val):
            self.__m_attrs |= ((1 << i))
        else:
            self.__m_attrs &= (~((1 << i)))

    @property
    def is_whitespace_before(self) -> bool:
        """ Наличие пробельных символов перед """
        return self.__getAttr(1)

    @is_whitespace_before.setter
    def is_whitespace_before(self, value) -> bool:
        self._setAttr(1, value)
        return value

    @property
    def is_whitespace_after(self) -> bool:
        """ Наличие пробельных символов после """
        return self.__getAttr(2)

    @is_whitespace_after.setter
    def is_whitespace_after(self, value) -> bool:
        self._setAttr(2, value)
        return value

    @property
    def is_newline_before(self) -> bool:
        """ Элемент начинается с новой строки.
         Для 1-го элемента всегда true. """
        return self.__getAttr(3)

    @is_newline_before.setter
    def is_newline_before(self, value) -> bool:
        self._setAttr(3, value)
        return value

    @property
    def is_newline_after(self) -> bool:
        """ Элемент заканчивает строку.
         Для последнего элемента всегда true. """
        return self.__getAttr(4)

    @is_newline_after.setter
    def is_newline_after(self, value) -> bool:
        self._setAttr(4, value)
        return value

    @property
    def inner_bool(self) -> bool:
        """ Это используется внутренним образом """
        return self.__getAttr(5)

    @inner_bool.setter
    def inner_bool(self, value) -> bool:
        self._setAttr(5, value)
        return value

    @property
    def not_noun_phrase(self) -> bool:
        """ Это используется внутренним образом 
         (признак того, что здесь не начинается именная группа, чтобы повторно не пытаться выделять) """
        return self.__getAttr(6)

    @not_noun_phrase.setter
    def not_noun_phrase(self, value) -> bool:
        self._setAttr(6, value)
        return value

    @property
    def whitespaces_before_count(self) -> int:
        """ Количество пробелов перед, переход на новую строку = 10, табуляция = 5 """
        if (self.previous is None):
            return 100
        if ((self.previous.end_char + 1) == self.begin_char):
            return 0
        return self.__calcWhitespaces(self.previous.end_char + 1,
                                      self.begin_char - 1)

    @property
    def newlines_before_count(self) -> int:
        """ Количество переходов на новую строку перед """
        ch0 = chr(0)
        res = 0
        txt = self.kit.sofa.text
        for p in range(self.begin_char - 1, -1, -1):
            ch = txt[p]
            if ((ord(ch)) == 0xA):
                res += 1
            elif ((ord(ch)) == 0xD and (ord(ch0)) != 0xA):
                res += 1
            elif (ch == '\f'):
                res += 10
            elif (not Utils.isWhitespace(ch)):
                break
            ch0 = ch
        return res

    @property
    def newlines_after_count(self) -> int:
        """ Количество переходов на новую строку перед """
        ch0 = chr(0)
        res = 0
        txt = self.kit.sofa.text
        p = self.end_char + 1
        while p < len(txt):
            ch = txt[p]
            if ((ord(ch)) == 0xD):
                res += 1
            elif ((ord(ch)) == 0xA and (ord(ch0)) != 0xD):
                res += 1
            elif (ch == '\f'):
                res += 10
            elif (not Utils.isWhitespace(ch)):
                break
            ch0 = ch
            p += 1
        return res

    @property
    def whitespaces_after_count(self) -> int:
        """ Количество пробелов перед, переход на новую строку = 10, табуляция = 5 """
        if (self.next0_ is None):
            return 100
        if ((self.end_char + 1) == self.next0_.begin_char):
            return 0
        return self.__calcWhitespaces(self.end_char + 1,
                                      self.next0_.begin_char - 1)

    def __calcWhitespaces(self, p0: int, p1: int) -> int:
        if ((p0 < 0) or p0 > p1 or p1 >= len(self.kit.sofa.text)):
            return -1
        res = 0
        i = p0
        while i <= p1:
            ch = self.kit.getTextCharacter(i)
            if (ch == '\r' or ch == '\n'):
                res += 10
                ch1 = self.kit.getTextCharacter(i + 1)
                if (ch != ch1 and ((ch1 == '\r' or ch1 == '\n'))):
                    i += 1
            elif (ch == '\t'):
                res += 5
            elif (ch == '\u0007'):
                res += 100
            elif (ch == '\f'):
                res += 100
            else:
                res += 1
            i += 1
        return res

    @property
    def is_hiphen(self) -> bool:
        """ Это символ переноса """
        ch = self.kit.sofa.text[self.begin_char]
        return LanguageHelper.isHiphen(ch)

    @property
    def is_table_control_char(self) -> bool:
        """ Это спец-символы для табличных элементов (7h, 1Eh, 1Fh) """
        ch = self.kit.sofa.text[self.begin_char]
        return (ord(ch)) == 7 or (ord(ch)) == 0x1F or (ord(ch)) == 0x1E

    @property
    def is_and(self) -> bool:
        """ Это соединительный союз И (на всех языках) """
        return False

    @property
    def is_or(self) -> bool:
        """ Это соединительный союз ИЛИ (на всех языках) """
        return False

    @property
    def is_comma(self) -> bool:
        """ Это запятая """
        return self.isChar(',')

    @property
    def is_comma_and(self) -> bool:
        """ Это запятая или союз И """
        return self.is_comma or self.is_and

    def isChar(self, ch: 'char') -> bool:
        """ Токен состоит из символа
        
        Args:
            ch('char'): проверяемый символ
        
        """
        if (self.begin_char != self.end_char):
            return False
        return self.kit.sofa.text[self.begin_char] == ch

    def isCharOf(self, chars_: str) -> bool:
        """ Токен состоит из одного символа, который есть в указанной строке
        
        Args:
            chars_(str): строка возможных символов
        
        """
        if (self.begin_char != self.end_char):
            return False
        return chars_.find(self.kit.sofa.text[self.begin_char]) >= 0

    def isValue(self, term: str, termua: str = None) -> bool:
        return False

    @property
    def is_letters(self) -> bool:
        """ Признак того, что это буквенный текстовой токен (TextToken) """
        return False

    @property
    def is_number(self) -> bool:
        """ Это число (в различных вариантах задания) """
        return False

    @property
    def is_referent(self) -> bool:
        """ Это сущность (Referent) """
        return False

    def getReferent(self) -> 'Referent':
        """ Ссылка на сущность (для ReferentToken) """
        return None

    def getReferents(self) -> typing.List['Referent']:
        """ Получить список ссылок на все сущности, скрывающиеся под элементом
         (дело в том, что одни сущности могут поглощать дркгие, например, адрес поглотит город)
        
        """
        return None

    def getNormalCaseText(self,
                          mc: 'MorphClass' = None,
                          single_number: bool = False,
                          gender: 'MorphGender' = MorphGender.UNDEFINED,
                          keep_chars: bool = False) -> str:
        """ Получить связанный с токеном текст в именительном падеже
        
        Args:
            mc(MorphClass): 
            single_number(bool): переводить ли в единственное число
        
        """
        return str(self)

    def getSourceText(self) -> str:
        """ Получить чистый фрагмент исходного текста
        
        """
        len0_ = (self.end_char + 1) - self.begin_char
        if ((len0_ < 1) or (self.begin_char < 0)):
            return None
        if ((self.begin_char + len0_) > len(self.kit.sofa.text)):
            return None
        return self.kit.sofa.text[self.begin_char:self.begin_char + len0_]

    def getMorphClassInDictionary(self) -> 'MorphClass':
        """ Проверка, что это текстовый токен и есть в словаре соотв. тип
        
        Args:
            cla: 
        
        """
        return self.morph.class0_

    def _serialize(self, stream: io.IOBase) -> None:
        from pullenti.ner.core.internal.SerializerHelper import SerializerHelper
        SerializerHelper.serializeInt(stream, self.begin_char)
        SerializerHelper.serializeInt(stream, self.end_char)
        SerializerHelper.serializeInt(stream, self.__m_attrs)
        SerializerHelper.serializeInt(stream, self.chars.value)
        if (self.__m_morph is None):
            self.__m_morph = MorphCollection()
        self.__m_morph._serialize(stream)

    def _deserialize(self, stream: io.IOBase, kit_: 'AnalysisKit',
                     vers: int) -> None:
        from pullenti.ner.core.internal.SerializerHelper import SerializerHelper
        self.kit = kit_
        self.begin_char = SerializerHelper.deserializeInt(stream)
        self.end_char = SerializerHelper.deserializeInt(stream)
        self.__m_attrs = (SerializerHelper.deserializeInt(stream))
        self.chars = CharsInfo._new2656(
            SerializerHelper.deserializeInt(stream))
        self.__m_morph = MorphCollection()
        self.__m_morph._deserialize(stream)
Пример #2
0
class Token:
    """ Базовый класс для всех токенов. Наследные классы - TextToken (конечная словоформа) и MetaToken (связный фрагмент других токенов).
    
    Токен
    """
    def __init__(self, kit_: 'AnalysisKit', begin: int, end: int) -> None:
        self.kit = None
        self.__m_begin_char = 0
        self.__m_end_char = 0
        self.tag = None
        self._m_previous = None
        self._m_next = None
        self.__m_morph = None
        self.chars = None
        self.__m_attrs = 0
        self.kit = kit_
        self.__m_begin_char = begin
        self.__m_end_char = end

    @property
    def begin_char(self) -> int:
        """ Позиция в тексте начального символа
        
        """
        return self.__m_begin_char

    @property
    def end_char(self) -> int:
        """ Позиция в тексте конечного символа
        
        """
        return self.__m_end_char

    @property
    def length_char(self) -> int:
        """ Длина в текстовых символах """
        return (self.end_char - self.begin_char) + 1

    @property
    def previous(self) -> 'Token':
        """ Предыдущий токен в цепочке токенов
        
        """
        return self._m_previous

    @previous.setter
    def previous(self, value) -> 'Token':
        self._m_previous = value
        if (value is not None):
            value._m_next = self
        self.__m_attrs = (0)
        return value

    @property
    def next0_(self) -> 'Token':
        """ Следующий токен в цепочке токенов
        
        """
        return self._m_next

    @next0_.setter
    def next0_(self, value) -> 'Token':
        self._m_next = value
        if (value is not None):
            value._m_previous = self
        self.__m_attrs = (0)
        return value

    @property
    def morph(self) -> 'MorphCollection':
        """ Морфологическая информация
        
        """
        if (self.__m_morph is None):
            self.__m_morph = MorphCollection()
        return self.__m_morph

    @morph.setter
    def morph(self, value) -> 'MorphCollection':
        self.__m_morph = value
        return value

    def __str__(self) -> str:
        return self.kit.sofa.text[self.begin_char:self.begin_char +
                                  (self.end_char + 1) - self.begin_char]

    def __get_attr(self, i: int) -> bool:
        ch = '\x00'
        if ((((self.__m_attrs) & 1)) == 0):
            self.__m_attrs = (1)
            if (self._m_previous is None):
                self._set_attr(1, True)
                self._set_attr(3, True)
            else:
                j = self._m_previous.end_char + 1
                while j < self.begin_char:
                    ch = self.kit.sofa.text[j]
                    if (Utils.isWhitespace((ch))):
                        self._set_attr(1, True)
                        if ((ord(ch)) == 0xD or (ord(ch)) == 0xA
                                or ch == '\f'):
                            self._set_attr(3, True)
                    j += 1
            if (self._m_next is None):
                self._set_attr(2, True)
                self._set_attr(4, True)
            else:
                j = self.end_char + 1
                while j < self._m_next.begin_char:
                    ch = self.kit.sofa.text[j]
                    if (Utils.isWhitespace(ch)):
                        self._set_attr(2, True)
                        if ((ord(ch)) == 0xD or (ord(ch)) == 0xA
                                or ch == '\f'):
                            self._set_attr(4, True)
                    j += 1
        return (((((self.__m_attrs) >> i)) & 1)) != 0

    def _set_attr(self, i: int, val: bool) -> None:
        if (val):
            self.__m_attrs |= ((1 << i))
        else:
            self.__m_attrs &= (~((1 << i)))

    @property
    def is_whitespace_before(self) -> bool:
        """ Наличие пробельных символов перед """
        return self.__get_attr(1)

    @is_whitespace_before.setter
    def is_whitespace_before(self, value) -> bool:
        self._set_attr(1, value)
        return value

    @property
    def is_whitespace_after(self) -> bool:
        """ Наличие пробельных символов после """
        return self.__get_attr(2)

    @is_whitespace_after.setter
    def is_whitespace_after(self, value) -> bool:
        self._set_attr(2, value)
        return value

    @property
    def is_newline_before(self) -> bool:
        """ Элемент начинается с новой строки.
        Для 1-го элемента всегда true. """
        return self.__get_attr(3)

    @is_newline_before.setter
    def is_newline_before(self, value) -> bool:
        self._set_attr(3, value)
        return value

    @property
    def is_newline_after(self) -> bool:
        """ Элемент заканчивает строку.
        Для последнего элемента всегда true. """
        return self.__get_attr(4)

    @is_newline_after.setter
    def is_newline_after(self, value) -> bool:
        self._set_attr(4, value)
        return value

    @property
    def inner_bool(self) -> bool:
        # Это используется внутренним образом
        return self.__get_attr(5)

    @inner_bool.setter
    def inner_bool(self, value) -> bool:
        self._set_attr(5, value)
        return value

    @property
    def not_noun_phrase(self) -> bool:
        # Это используется внутренним образом
        # (признак того, что здесь не начинается именная группа, чтобы повторно не пытаться выделять)
        return self.__get_attr(6)

    @not_noun_phrase.setter
    def not_noun_phrase(self, value) -> bool:
        self._set_attr(6, value)
        return value

    @property
    def whitespaces_before_count(self) -> int:
        """ Количество пробелов перед, переход на новую строку = 10, табуляция = 5 """
        if (self.previous is None):
            return 100
        if ((self.previous.end_char + 1) == self.begin_char):
            return 0
        return self.__calc_whitespaces(self.previous.end_char + 1,
                                       self.begin_char - 1)

    @property
    def newlines_before_count(self) -> int:
        """ Количество переходов на новую строку перед """
        ch0 = chr(0)
        res = 0
        txt = self.kit.sofa.text
        for p in range(self.begin_char - 1, -1, -1):
            ch = txt[p]
            if ((ord(ch)) == 0xA):
                res += 1
            elif ((ord(ch)) == 0xD and (ord(ch0)) != 0xA):
                res += 1
            elif (ch == '\f'):
                res += 10
            elif (not Utils.isWhitespace(ch)):
                break
            ch0 = ch
        return res

    @property
    def newlines_after_count(self) -> int:
        """ Количество переходов на новую строку перед """
        ch0 = chr(0)
        res = 0
        txt = self.kit.sofa.text
        p = self.end_char + 1
        while p < len(txt):
            ch = txt[p]
            if ((ord(ch)) == 0xD):
                res += 1
            elif ((ord(ch)) == 0xA and (ord(ch0)) != 0xD):
                res += 1
            elif (ch == '\f'):
                res += 10
            elif (not Utils.isWhitespace(ch)):
                break
            ch0 = ch
            p += 1
        return res

    @property
    def whitespaces_after_count(self) -> int:
        """ Количество пробелов перед, переход на новую строку = 10, табуляция = 5 """
        if (self.next0_ is None):
            return 100
        if ((self.end_char + 1) == self.next0_.begin_char):
            return 0
        return self.__calc_whitespaces(self.end_char + 1,
                                       self.next0_.begin_char - 1)

    def __calc_whitespaces(self, p0: int, p1: int) -> int:
        if ((p0 < 0) or p0 > p1 or p1 >= len(self.kit.sofa.text)):
            return -1
        res = 0
        i = p0
        while i <= p1:
            ch = self.kit.get_text_character(i)
            if (ch == '\r' or ch == '\n'):
                res += 10
                ch1 = self.kit.get_text_character(i + 1)
                if (ch != ch1 and ((ch1 == '\r' or ch1 == '\n'))):
                    i += 1
            elif (ch == '\t'):
                res += 5
            elif (ch == '\u0007'):
                res += 100
            elif (ch == '\f'):
                res += 100
            else:
                res += 1
            i += 1
        return res

    @property
    def is_hiphen(self) -> bool:
        """ Это символ переноса """
        ch = self.kit.sofa.text[self.begin_char]
        return LanguageHelper.is_hiphen(ch)

    @property
    def is_table_control_char(self) -> bool:
        """ Это спец-символы для табличных элементов (7h, 1Eh, 1Fh) """
        ch = self.kit.sofa.text[self.begin_char]
        return (ord(ch)) == 7 or (ord(ch)) == 0x1F or (ord(ch)) == 0x1E

    @property
    def is_and(self) -> bool:
        """ Это соединительный союз И (на всех языках) """
        return False

    @property
    def is_or(self) -> bool:
        """ Это соединительный союз ИЛИ (на всех языках) """
        return False

    @property
    def is_comma(self) -> bool:
        """ Это запятая """
        return self.is_char(',')

    @property
    def is_comma_and(self) -> bool:
        """ Это запятая или союз И """
        return self.is_comma or self.is_and

    def is_char(self, ch: 'char') -> bool:
        """ Токен состоит из конкретного символа
        
        Args:
            ch('char'): проверяемый символ
        
        """
        if (self.begin_char != self.end_char):
            return False
        return self.kit.sofa.text[self.begin_char] == ch

    def is_char_of(self, chars_: str) -> bool:
        """ Токен состоит из одного символа, который есть в указанной строке
        
        Args:
            chars_(str): строка возможных символов
        
        """
        if (self.begin_char != self.end_char):
            return False
        return chars_.find(self.kit.sofa.text[self.begin_char]) >= 0

    def is_value(self, term: str, termua: str = None) -> bool:
        """ Проверка конкретного значения слова
        
        Args:
            term(str): слово (проверяется значение TextToken.Term)
            termua(str): слово для проверки на украинском языке
        
        Returns:
            bool: да-нет
        """
        return False

    @property
    def is_letters(self) -> bool:
        """ Признак того, что это буквенный текстовой токен (TextToken) """
        return False

    def get_referent(self) -> 'Referent':
        """ Получить ссылку на сущность (не null только для ReferentToken)
        
        """
        return None

    def get_referents(self) -> typing.List['Referent']:
        """ Получить список ссылок на все сущности, скрывающиеся под элементом.
        Дело в том, что одни сущности могут накрывать другие (например, адрес накроет город).
        
        """
        return None

    def get_normal_case_text(self,
                             mc: 'MorphClass' = None,
                             num: 'MorphNumber' = MorphNumber.UNDEFINED,
                             gender: 'MorphGender' = MorphGender.UNDEFINED,
                             keep_chars: bool = False) -> str:
        """ Получить связанный с токеном текст в именительном падеже
        
        Args:
            mc(MorphClass): желательная часть речи
            num(MorphNumber): желательное число
            gender(MorphGender): желательный пол
            keep_chars(bool): сохранять регистр символов (по умолчанию, всё в верхний)
        
        Returns:
            str: строка текста
        """
        return str(self)

    def get_source_text(self) -> str:
        """ Получить фрагмент исходного текста, связанный с токеном
        
        Returns:
            str: фрагмент исходного текста
        """
        len0_ = (self.end_char + 1) - self.begin_char
        if ((len0_ < 1) or (self.begin_char < 0)):
            return None
        if ((self.begin_char + len0_) > len(self.kit.sofa.text)):
            return None
        return self.kit.sofa.text[self.begin_char:self.begin_char + len0_]

    def get_morph_class_in_dictionary(self) -> 'MorphClass':
        """ Проверка, что слово есть в словаре соответствующего языка
        
        Returns:
            MorphClass: части речи, если не из словаря, то IsUndefined
        """
        return self.morph.class0_

    def _serialize(self, stream: Stream) -> None:
        from pullenti.ner.core.internal.SerializerHelper import SerializerHelper
        SerializerHelper.serialize_int(stream, self.begin_char)
        SerializerHelper.serialize_int(stream, self.end_char)
        SerializerHelper.serialize_int(stream, self.__m_attrs)
        SerializerHelper.serialize_int(stream, self.chars.value)
        if (self.__m_morph is None):
            self.__m_morph = MorphCollection()
        self.__m_morph._serialize(stream)

    def _deserialize(self, stream: Stream, kit_: 'AnalysisKit',
                     vers: int) -> None:
        from pullenti.ner.core.internal.SerializerHelper import SerializerHelper
        self.kit = kit_
        self.__m_begin_char = SerializerHelper.deserialize_int(stream)
        self.__m_end_char = SerializerHelper.deserialize_int(stream)
        self.__m_attrs = (SerializerHelper.deserialize_int(stream))
        self.chars = CharsInfo._new2561(
            SerializerHelper.deserialize_int(stream))
        self.__m_morph = MorphCollection()
        self.__m_morph._deserialize(stream)