Перейти к содержанию

Подсветка текста

HighlightedText(source, layers=None, long_sent_word_factor=20, complex_syl_factor=4, stopwords=None, cliches=None, alliteration_threshold=0.001)

Подсветка текста по слоям в духе сервисов проверки стиля: каждый слой отмечает фрагменты текста, которые считает статистика, - длинные предложения, сложные слова, пассив. Источник данных - текст или объект класса Doc библиотеки spaCy. Результат отображается в Jupyter как HTML со стилями и легендой; to_html возвращает разметку, а highlights хранит фрагменты для собственной отрисовки. Фрагменты разных слоев могут пересекаться.

Исключения:

  • SourceTypeError - источник, который не строка и не Doc;
  • SourceError - источник без слов;
  • ParameterError - слои, которые не имя и не список имен, неизвестный слой или слой, которому нужна разметка, отсутствующая у источника.
highlight(source, layers=None, long_sent_word_factor=20, complex_syl_factor=4, stopwords=None, cliches=None, alliteration_threshold=0.001)

Функция highlight возвращает объект HighlightedText ruTS со слоями в стиле сервисов Главред и Тургенев: длинные предложения, сложные и редкие слова, пассив, обороты, цепочки родительных падежей, расщепленные сказуемые, отглагольные существительные, производные предлоги, штампы, стоп-слова, вводные слова, коннекторы, аллитерации. Одна картинка объясняет, из чего складываются значения метрик, лучше таблицы чисел.

Группа Слой Что отмечает Статистика
Читаемость long_sents Предложения с числом слов не меньше long_sent_word_factor BasicStats, ReadabilityStats
complex_words Слова с числом слогов не меньше complex_syl_factor BasicStats, ReadabilityStats
rare_words Слова с леммой вне вшитого списка топ-10000; числа, латиница, сокращения и стоп-слова не подсвечиваются LexicalStats
Синтаксис passive Пассивные глагольные формы вместе со вспомогательным глаголом SyntaxStats
participle_clauses Причастные обороты SyntaxStats
converb_clauses Деепричастные обороты SyntaxStats
genitive_chains Цепочки родительных падежей вместе с управляющим словом SyntaxStats
split_predicates Расщепленные сказуемые от глагола до именной части SyntaxStats
Канцелярит verbal_nouns Отглагольные существительные StyleStats
compound_prepositions Производные предлоги по списку COMPOUND_PREPOSITIONS StyleStats
cliches Штампы по списку OFFICIALESE_CLICHES или параметру cliches StyleStats
Стиль stopwords Слова «воды» по части речи (is_water_word) или переданному списку StyleStats
parentheticals Вводные слова и обороты StyleStats
connectors Коннекторы по части речи из разметки Doc или ruMorph, в подсказке класс и тип CohesionStats
Фоника alliteration Повторы согласной в соседних словах, маловероятные при частотах букв русского языка PhonStats

Группы заданы в ruts.constants.HIGHLIGHT_LAYER_GROUPS. Слои группы «Синтаксис» считаются по дереву зависимостей и доступны только для объекта Doc с разбором зависимостей (рекомендуемый конвейер или модели ru_core_news_sm, ru_core_news_md, ru_core_news_lg). По умолчанию включаются слои HIGHLIGHT_DEFAULT_LAYERS - длинные предложения, сложные слова, пассив, цепочки родительных, расщепленные сказуемые, штампы - из доступных источнику; layers="all" включает все доступные. Пятнадцать слоев сразу перекрывают друг друга (производный предлог состоит из стоп-слов, коннектор может быть вводным словом), поэтому выбирайте нужные.

Аллитерация

Аллитерация ищется внутри предложения как цепочка из двух и более соседних слов, в основе каждого из которых есть одна и та же согласная буква. Основа - общая начальная часть словоформы и ее леммы по ruMorph (крупных → крупны, руках → рука): окончания согласуются с соседними словами и повторяют согласные по грамматике, а не по звучанию (этих крупных, своим целям и нуждам). Вероятность цепочки при независимом распределении букв - произведение по словам вероятностей встретить согласную среди букв основы, \(1 - (1 - f)^n\), где \(f\) - частота согласной в русских текстах, \(n\) - число букв основы; цепочка подсвечивается, если вероятность ниже порога alliteration_threshold. На каждой позиции проверяется около двадцати согласных, поэтому порог строгий: на прозе при 0.001 подсвечено около 5% слов, при 0.01 - около 20%, в основном случайные совпадения частых букв. Повтор редкой согласной (слышно, бесшумно шуршат камыши) заметен в двух-трех словах, повтор частой в длинных словах ожидаем и не подсвечивается. Слова короче трех букв, стоп-слова и слова без гласных цепочку не прерывают и не продолжают, буква й не учитывается, так как в именительном падеже входит в лемму прилагательного. Индекс аллитерации PhonStats измеряет сгруппированность повторов во всем тексте, подсветка показывает их места.

Класс расширяет HighlightedText ядра anyTS крючками русского языка из ruts.constants: слои с их названиями в легенде - HIGHLIGHT_LAYERS_DESC, слои по умолчанию - HIGHLIGHT_DEFAULT_LAYERS, разметка Doc, которая нужна слою, - HIGHLIGHT_LAYER_ANNOTATIONS (синтаксическим слоям нужен только разбор зависимостей, так как леммы берутся из ruMorph), стили слоев - HIGHLIGHT_LAYER_STYLES; префикс классов CSS - ruts. Слова строки выделяются так же, как в WordsExtractor, предложения - anySeg; Doc без границ предложений (spacy.blank, пайплайн без parser и senter) тоже делится на предложения anySeg, поэтому для него доступен слой long_sents, а части дефисного слова Doc составляют одно слово. Фрагменты слоев, кроме пассива, оборотов и цепочек родительных, находят искатели ядра с русскими крючками: слоги count_syllables, сравнение без буквы ё (normalize_yo), сопоставитель коннекторов RussianConnectorMatcher с частями речи connector_pos, основы get_stem и частоты согласных RU_LETTER_FREQUENCIES без й для аллитерации.

from ruts import load_pipeline
from ruts.visualizers import highlight

nlp = load_pipeline()
text = (
    "Проект, подготовленный за неделю, был одобрен советом без обсуждения. "
    "Повышение эффективности использования бюджетных средств обсуждалось, не выходя за рамки регламента. "
    "Участники, представлявшие региональные министерства, не смогли согласовать позиции по вопросам "
    "финансирования и распределения ответственности между ведомствами, поскольку каждое из них "
    "настаивало на собственной трактовке положений соглашения. "
    "Споры стихли, в кулуарах шумно шептались и шушукались, а решение было отложено "
    "до следующего заседания."
)
ht = highlight(nlp(text))
ht.counts
ht.highlights[:2]
highlight(nlp(text), layers="all").counts
{'long_sents': 1,
 'complex_words': 26,
 'passive': 4,
 'genitive_chains': 2,
 'split_predicates': 0,
 'cliches': 1}
(Highlight(start=8, end=22, layer='complex_words', note='сложное слово, 5 слогов'),
 Highlight(start=8, end=22, layer='passive', note='пассив без агенса'))
{'long_sents': 1,
 'complex_words': 26,
 'rare_words': 3,
 'passive': 4,
 'participle_clauses': 2,
 'converb_clauses': 1,
 'genitive_chains': 2,
 'split_predicates': 0,
 'verbal_nouns': 10,
 'compound_prepositions': 0,
 'cliches': 1,
 'stopwords': 7,
 'parentheticals': 0,
 'connectors': 4,
 'alliteration': 1}

В Jupyter объект ht отображается так (наведите курсор на фрагмент, чтобы увидеть пояснение):

Длинные предложения1Сложные слова26Пассив4Цепочки родительных2Расщеплённые сказуемые0Штампы1
Проект, подготовленный за неделю, был одобрен советом без обсуждения. Повышение эффективности использования бюджетных средств обсуждалось, не выходя за рамки регламента. Участники, представлявшие региональные министерства, не смогли согласовать позиции по вопросам финансирования и распределения ответственности между ведомствами, поскольку каждое из них настаивало на собственной трактовке положений соглашения. Споры стихли, в кулуарах шумно шептались и шушукались, а решение было отложено до следующего заседания.

Подсветка по строке без модели spaCy включает все слои, кроме синтаксических: по умолчанию длинные предложения, сложные слова и штампы.

text = "Чуть слышно, бесшумно шуршат камыши. Повышение эффективности использования ресурсов обсуждалось."
highlight(text, layers=["complex_words", "alliteration"]).highlights
(Highlight(start=5, end=35, layer='alliteration', note='аллитерация на «ш»'),
 Highlight(start=37, end=46, layer='complex_words', note='сложное слово, 5 слогов'),
 Highlight(start=47, end=60, layer='complex_words', note='сложное слово, 5 слогов'),
 Highlight(start=61, end=74, layer='complex_words', note='сложное слово, 6 слогов'),
 Highlight(start=84, end=95, layer='complex_words', note='сложное слово, 4 слога'))

Параметры

Параметр Тип По умолчанию Описание
source str / Doc - Источник данных (строка или объект Doc)
layers list[str] / str None Слои подсветки; если не заданы, включаются слои по умолчанию, доступные источнику; "all" - все доступные

Параметры слоев ruTS:

Параметр Тип По умолчанию Описание
long_sent_word_factor int 20 Минимальное количество слов в длинном предложении
complex_syl_factor int 4 Минимальное количество слогов в сложном слове
stopwords list[str] / set[str] None Список или множество слов «воды»; если не задан, они определяются по части речи с помощью ruMorph
cliches list[str] / set[str] None Список или множество штампов; если не задан, используется OFFICIALESE_CLICHES
alliteration_threshold float 0.001 Порог вероятности повтора согласной при независимом распределении букв, ниже которого повтор считается аллитерацией

Порог, который не целое число не меньше единицы, или вероятность вне интервала (0, 1] дают ParameterError, стоп-слова или штампы, которые не строки, - SourceTypeError.

Атрибуты

Атрибут Тип Описание
text str Текст источника данных
layers tuple[str] Включенные слои в порядке отрисовки
highlights tuple[Highlight] Подсвеченные фрагменты, упорядоченные по началу, затем по убыванию конца
counts dict[str, int] Количество фрагментов каждого слоя
Highlight(start, end, layer, note='')

Фрагмент подсветки: неизменяемый объект с параметрами в роли полей.

Поле Тип По умолчанию Описание
start int - Позиция первого символа фрагмента в тексте
end int - Позиция после последнего символа фрагмента
layer str - Слой подсветки
note str '' Пояснение фрагмента для всплывающей подсказки

Пояснение фрагмента ruTS - число слов в предложении, слогов в слове, длина цепочки или согласная аллитерации.

Методы

to_html(legend=True, css=True) возвращает HTML-разметку подсвеченного текста: блок div с классом <префикс>-highlight, в котором легенда со счетчиками и текст, где подсвеченный отрезок - span с классами <префикс>-hl и <префикс>-hl-<слой> с пояснениями в его title; <префикс> - css_prefix. Пересекающиеся фрагменты разных слоев дают отрезки с несколькими классами в порядке отрисовки. Переносы строк (\n, \r\n, \r) становятся символьными ссылками, по одной на перенос, поэтому разметку можно вставлять в Markdown.

Параметр Тип По умолчанию Описание
legend bool True Добавлять легенду со счетчиками фрагментов
css bool True Добавлять стили слоев

Метод класса css() возвращает стили, которые добавляет to_html: стили контейнера, легенды и текста под классами css_prefix, объявления layer_styles для каждого слоя и темный цвет текста на слоях с фоном.

alliteration = highlight("Чуть слышно, бесшумно шуршат камыши.", layers="alliteration")
alliteration.to_html(legend=False, css=False)
'<div class="ruts-highlight"><div class="ruts-highlight-text">Чуть <span class="ruts-hl ruts-hl-alliteration" title="аллитерация на «ш»">слышно, бесшумно шуршат камыши</span>.</div></div>'