detect.py: classify_sheet (ОСВ / форма ББ-ОФР / прочее по словарю), find_table_header (строка с ≥ 2 группами сумм, «Дебет/Кредит» под группой в пределах merged-диапазона или до следующей группы, заголовок в 1–4 строки, в т.ч. «Нач. сальдо Дт» в одной ячейке; без «начала»; свёрнутое сальдо в *_debit + collapsed; свёрнутые «Обороты» и половинчатая пара Дт/Кт — InvalidFormatError с названием группы), text_col, inn_col (заголовок «ИНН» или ≥ 80 % значений из 10/12 цифр), right_edge, extra_cols, group_label_rows, first_data_row, is_header_repeat (две группы или копия строки блока). Pattern.search_normalized — ячейка нормализуется один раз (T3.6). osv_groups: известные группировки OTHER перечислены явно, чтобы строка-метка «Основные средства» в неслитом заголовке была частью блока. Хелпер тестов gridbuilder (Sheet из «картинки»). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
39 lines
4.5 KiB
Markdown
39 lines
4.5 KiB
Markdown
# 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` | маркер листа ОСВ и листов форм ББ/ОФР; группы сумм (начало / обороты / конец); «Дебет»/«Кредит»; служебные колонки (ИНН, КПП, код, количество, валюта); строка «Итого»; метки шапки (счёт, период, выводимые данные, валюта, параметры, субконто) |
|
||
| `osv_groups.yaml` | название группировки из шапки -> `ACCOUNT` / `DEPARTMENT` / `COUNTERPARTY` / `CONTRACT` / `OTHER` (`default` — для всего прочего) |
|
||
| `periods.yaml` | текст периода -> `period_quarter` и `is_cumulative` (§1.5); `year` — паттерн года |
|
||
| `data_types.yaml` | «Выводимые данные» -> `BU` / `NU` / `SUM`; строки «Вал.» / «Кол.»; коды валют ISO 4217; синонимы валюты (`руб.` -> `RUB`) |
|
||
|
||
## Как писать паттерны
|
||
|
||
- Паттерн — регулярное выражение 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` при
|
||
загрузке с именем файла и ключом.
|
||
|
||
## Что намеренно не в штатном словаре
|
||
|
||
Синоним «нач. остаток» / «начальный остаток» для группы `opening` не включён: он нужен, чтобы показать, что новый
|
||
формат подключается строкой в YAML (тест сценария «Новый синоним»).
|