goon/app/normalize/text.py
goon-foss a4486980a4 style: myslniki em/en z komentarzy i docstringow (calosc repo)
1745 wystapien w 291 plikach (backend, scripts, mobile). Dominowal jeden ksztalt,
' — ' laczace zdania, wiec poszedl przecinek; myslnik otwierajacy mysl zdjety;
zakresy 0–5 i A–Z na dywiz.

Podzial komentarz/kod robil skaner stanow, nie regex, zeby nie ruszyc myslnika
stojacego w stringu albo w wyrazeniu regularnym. Potwierdzone maszynowo: po wycieciu
komentarzy z wersji HEAD i z dysku obie sa identyczne we wszystkich 291 plikach,
czyli poza komentarzami nie zmienilo sie nic. 233 pliki .py parsuja sie bez bledu,
tsc ma te same 11 bledow w tych samych 3 plikach co przed zmiana.

Dwie rzeczy wymagaly poprawki po automacie: wyrownane listy definicji, gdzie myslnik
byl separatorem kolumny (37 miejsc, kolumna przywrocona), i trzy przeniesienia mysli
do nowej linii, gdzie zostawal wiszacy przecinek na poczatku (poprawione recznie).

Bundla nie republikuje: Hermes i tak nie niesie komentarzy, wiec dla uzytkownika
to zero zmiany.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 11:51:57 +02:00

61 lines
1.8 KiB
Python

"""Normalizacja tekstu używana wszędzie w pipeline'ie matchingu.
Cel: dwie formy tej samej nazwy (różne casing, akcenty, interpunkcja, whitespace, „the"/myślniki)
muszą produkować identyczny string po `normalize`. Trgram index na tych polach robi resztę.
"""
from __future__ import annotations
import re
import unicodedata
from slugify import slugify as _slugify
_NON_ASCII_ALNUM_RE = re.compile(r"[^a-z0-9\s]+")
_WS_RE = re.compile(r"\s+")
_LEADING_ARTICLE_RE = re.compile(r"^(the|a|an)\s+", flags=re.IGNORECASE)
# Litery których NFKD nie rozkłada na ASCII, mapujemy ręcznie.
_EXTRA_TRANSLIT = str.maketrans(
{
"Ł": "L", "ł": "l",
"Ø": "O", "ø": "o",
"Æ": "AE", "æ": "ae",
"Œ": "OE", "œ": "oe",
"Þ": "Th", "þ": "th",
"Ð": "D", "ð": "d",
"Đ": "D", "đ": "d",
"ß": "ss",
"Ħ": "H", "ħ": "h",
}
)
def strip_accents(value: str) -> str:
pre = value.translate(_EXTRA_TRANSLIT)
nfkd = unicodedata.normalize("NFKD", pre)
return "".join(c for c in nfkd if not unicodedata.combining(c))
def normalize(value: str | None) -> str:
"""Lower + strip accents + remove punctuation + collapse whitespace + drop leading article."""
if not value:
return ""
out = strip_accents(value).lower()
out = _NON_ASCII_ALNUM_RE.sub(" ", out)
out = _WS_RE.sub(" ", out).strip()
out = _LEADING_ARTICLE_RE.sub("", out)
return out
def normalize_person(value: str | None) -> str:
"""Normalizacja imion: jak `normalize`, plus zwija inicjały „M." → „m"."""
if not value:
return ""
out = normalize(value)
return _WS_RE.sub(" ", out).strip()
def slugify(value: str | None) -> str:
if not value:
return ""
return _slugify(value, lowercase=True, max_length=200)