Andrey Epifancev 746d993077 fix(normalizer): замена неразрывного пробела в fix_lookalikes, тест
Исправлена строка 26 в fix_lookalikes: текст.replace("\xa0", " ") для
корректной замены неразрывного пробела (U+00A0) на обычный пробел (U+0020),
как в источнике date_utils._normalize.

Добавлен тест test_nbsp_replacement для проверки замены NBSP с таблицей
двойников и без неё.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 00:00:31 +04:00

105 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Очистка OCR-текста (§11.1 п. 1, 6; D-4 `text.py`): перенос функций старого ядра, поведение — как в источнике."""
import pytest
from src.normalizer.ocr.text import (
clean_value,
collapse_whitespace,
digits_only,
fix_lookalikes,
is_code_header,
is_value_header,
normalize_header,
)
LOOKALIKES = {
"О": "0",
"о": "0",
"O": "0",
"o": "0",
"З": "3",
"з": "3",
"l": "1",
"I": "1",
"|": "1",
"і": "1",
"б": "6",
"S": "5",
"s": "5",
"Ч": "4",
}
class TestFixLookalikes:
@pytest.mark.parametrize(
("raw", "expected"),
[
("2ОО5", "2005"), # два прохода: О после 2, затем О после 0
("3l.12.2О24", "31.12.2024"),
("Общество", "Общество"), # буквы без соседней цифры не трогаются
("2|0|2|4|", "2 0 2 4 "), # первая строка — только цифры и |: это разделитель клеток
("3l", "31"), # | не разделитель, если есть буквы
("", ""),
],
)
def test_replaces_only_next_to_digits(self, raw: str, expected: str) -> None:
assert fix_lookalikes(raw, LOOKALIKES) == expected
def test_separator_rule_looks_at_first_line_only(self) -> None:
assert fix_lookalikes("2|0|2|4|\nмусор", LOOKALIKES) == "2 0 2 4 \nмусор"
def test_empty_table_keeps_text(self) -> None:
assert fix_lookalikes("2ОО5", {}) == "2ОО5"
def test_nbsp_replacement(self) -> None:
# неразрывный пробел (U+00A0) → обычный пробел (U+0020)
assert fix_lookalikes("31\xa012\xa02024", LOOKALIKES) == "31 12 2024"
assert fix_lookalikes("31\xa012\xa02024", {}) == "31 12 2024"
@pytest.mark.parametrize(
("raw", "expected"),
[
("13 070", "13 070"),
("(7744536}", "7744536"),
("изо :", "изо"),
("На 30 июня\n2025 г", "На 30 июня 2025 г"),
("", ""),
],
)
def test_clean_value(raw: str, expected: str) -> None:
assert clean_value(raw) == expected
def test_digits_only() -> None:
assert digits_only("3|1 21 2| о! О' 0 0; 3: 51") == "3121200351"
assert digits_only("+") == ""
def test_collapse_whitespace() -> None:
assert collapse_whitespace(" На 31 декабря\n2024 г.\t") == "На 31 декабря 2024 г."
class TestHeaders:
def test_normalize_header(self) -> None:
assert normalize_header("Наименование\nпоказателя:") == "наименование показателя"
assert normalize_header(None) == ""
def test_code_header(self) -> None:
assert is_code_header(normalize_header("Код"))
assert is_code_header(normalize_header("Код строки"))
assert not is_code_header(normalize_header("Наименование"))
@pytest.mark.parametrize(
("text", "expected"),
[
("на 30 июня 2025 г", True),
("за январь июнь 2025 г", True),
("2024", True),
("пояснения", False),
("", False),
],
)
def test_value_header(self, text: str, expected: bool) -> None:
assert is_value_header(text) is expected