Refs #14 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b
11 KiB
rules/ — словари синонимов парсера
Словари rules/*.yaml, по которым tabular-parser ищет структуру файла по содержимому: заголовки колонок,
группировки, периоды, типы данных. Словари — данные, а не код: новый синоним добавляется строкой в YAML без
правки парсера. Парсер не привязан к координатам (буквы колонок, номера строк, имена листов); это проверяет
AST-линтер tests/unit/parser/test_no_coordinates.py.
Путь указан относительно api/ (рабочего каталога команд сервиса): api/rules/. Загрузчик — src/parser/rules.py
(load_rules()), источник содержимого — docs/context/05-domain-rules.md §1.0–§1.5.
| Файл | Ключи | Что описывает |
|---|---|---|
osv_headers.yaml |
sheet_markers, groups (opening/turnover/closing), debit, credit, service_columns (только inn), total_row, total_row_secondary («Итого развернутое»), column_captions («Код»/«Наименование» под названием группировки), counterparty_inn_suffix / inn_only_row / inn_kpp_cell (ИНН в тексте названия, строкой выше, «ИНН/КПП» в ячейке; обязательные именованные группы tail, inn), header_markers (account, period, data_type, currency, org_params, subkonto) |
признак листа ОСВ; группы сумм (начало / обороты / конец); «Дебет»/«Кредит»; колонка ИНН (прочие колонки таблицы попадают в rows[].extra под своим заголовком и в словаре не нужны); строка «Итого»; метки шапки |
osv_groups.yaml |
mapping, default |
название группировки из шапки -> ACCOUNT / DEPARTMENT / COUNTERPARTY / CONTRACT / OTHER (default — для всего прочего) |
periods.yaml |
rules (pattern, quarter, is_cumulative), year, end, months (названия месяцев, группы m01…m12), range (диапазон месяцев с годами, группы m1, y1, m2, y2), standalone (период отдельной ячейкой без метки) |
текст периода -> period_quarter и is_cumulative (§1.5, ASSUMPTION(OQ-02)); year — паттерн года, end — конец текста периода в строке шапки («г.», «год») |
data_types.yaml |
header, standalone_header (тип данных отдельной ячейкой без метки), row, currency_codes, currency_aliases |
«Выводимые данные» -> BU / NU / SUM; строки «Вал.» / «Кол.» -> CURRENCY / QUANTITY; коды валют ISO 4217 (строка, равная коду, — валютная); написания валюты в шапке (руб. -> RUB; ключ алиаса обязан быть в currency_codes) |
statement_headers.yaml |
form_titles (BALANCE / INCOME / DISCLOSURE), okud (коды ОКУД по типам), continuation (маркер страницы-продолжения), code_caption, name_caption, explanations_caption, column_numbering, labels (метки шапки документа: organization, inn, okpo, okved, okopf, okfs, okopf_okfs, okei, units, address, date, okud_label), auditor (строка блока аудитора), legal_form (признак названия организации), line_codes (диапазоны кодов строк, доля и минимум кодов в колонке) |
заголовок и тип формы ББ/ОФР (баланс / отчет о финансовых результатах / пояснения и расшифровки); ОКУД -> тип; признак продолжения страницы; подписи колонок таблицы; метки и структура шапки документа; диапазоны четырёхзначных кодов строк (§12) |
statement_periods.yaml |
months (названия месяцев, группы m01…m12), on_date (дата вида «на 31 декабря 2024 г.», группы d, m, y), numeric_date (дата вида «31.12.2024», группы d, m, y), for_months (период вида «за 9 месяцев 2025 г.», группы n, y), for_range (диапазон месяцев вида «за январь–сентябрь 2025 г.», группы m, y), for_year (год вида «за 2024 г.» или «2024») |
текст заголовка колонки или подзаголовка формы ББ/ОФР -> дата конца периода (§12 п. 4) |
statement_checks.yaml |
tolerance (допуск в единицах формы), subline_check (проверка суммы пятизначных подстрок = родитель), relations (список соотношений: form, relation («код = код [+ |
-] код …»), strict, abs_terms) |
Как писать паттерны
- Паттерн — регулярное выражение Python. Он ищется (
search) в нормализованном тексте ячейки и применяется без учёта регистра. - Нормализация текста (
normalize_text): нижний регистр, «ё» -> «е», дефисы, тире, неразрывные пробелы и переносы строк -> один пробел, пробелы схлопываются. Пример:Оборотно-сальдовая\nведомость->оборотно сальдовая ведомость. - Поэтому в паттернах нет «ё», дефисов, тире и диапазонов
[а-я]: пишитеоборотно\s*сальдовая,д т(для «Д-т»),\wвместо диапазона. Загрузчик отвергает такой паттерн с указанием файла и ключа. - Порядок записей в списках
mapping,rules(периоды),header,row— приоритет: побеждает первое совпадение, от специфичных правил к общим. - В
osv_groups.yamlизвестные группировкиOTHER(«Основные средства», «Номенклатура», «Статьи затрат», …) перечислены вmappingявно, хотяdefaultи так даётOTHER: детектор заголовка таблицы (src/parser/detect.py) считает строку под «Дебет/Кредит» частью блока заголовка, только если её текст совпал с записьюmapping, сИННили с «субконто». Новая группировка в отдельной строке заголовка = новая строка вmapping. - Ошибка в словаре (нет обязательного ключа, неизвестный ключ, неверный регэксп или тип) —
RuntimeErrorпри загрузке с именем файла и ключом.
Покрытие словарей
Каждая запись распознавания (один Pattern в любом из словарей: sheet_markers,
groups, debit, credit, service_columns, total_row, header_markers, mapping, правила и year/end
периодов, header/row/currency_aliases типов данных) должна сработать хотя бы раз на реальных ОСВ или синтетике:
это проверяет tests/fixtures/test_rules_coverage.py (счётчик совпадений Pattern, сообщение — файл, ключ и паттерн
несработавших записей). Перечень currency_codes — список значений ISO 4217, а не синонимы, в покрытие не входит (решение R-22).
Несработавшая запись — либо мёртвый синоним (удалить из YAML вместе с тестом словаря), либо пробел в фикстурах
(добавить файл синтетики s1x_… с описанием в README fixtures). Так удалены service_columns.kpp|code|quantity|currency:
код читает только inn, остальные колонки идут в extra. Синтетика s14–s16 закрывает остальные записи, которых нет в
реальных ОСВ (формы ББ/ОФР по одному признаку, названия групп сумм «Входящее/Начальное/Конечное/Исходящее сальдо»,
шапка без организации, период «2024», «Детализация: …», группировки OTHER).
Как добавить синоним
- Найдите словарь и ключ по таблице выше; добавьте строку-паттерн в нужный список (первое совпадение побеждает —
ставьте специфичное выше общего). Пример: заголовок «Нач. остаток» вместо «Сальдо на начало» —
groups.openingвosv_headers.yaml:- 'нач\.\s*остаток'. - Положите файл с этим форматом в
../fixtures/osv/(реальный) или добавьте синтетику вtests/synthetic/generate.py(с описанием в README fixtures); иначе тест покрытия сочтёт запись мёртвой. make golden-update, просмотрите diff, закоммитьте снимки в репозитории fixtures. Код парсера не меняется.
Что намеренно не в штатном словаре
Синоним «нач. остаток» / «начальный остаток» для группы opening не включён: он нужен, чтобы показать, что новый
формат подключается строкой в YAML (тест сценария «Новый синоним»).