fix: нормализация КАПСа по словам (город + должности)
- раньше: если в тексте есть аббревиатура (ООО, И.О.) или цифры (индекс в адресе) — весь текст оставался КАПСОМ - теперь: каждое слово нормализуется отдельно, аббревиатуры (АРМ, СКУД, ООО, ИНН и т.п.) и инициалы сохраняются - город: '350000, Г. КРАСНОДАР...' → 'Г. Краснодар' → город снова определяется при импорте - должность: 'ГЛАВА' → 'Глава', ФИО: 'ИВАНОВ ИВАН ИВАНОВИЧ' → 'Иванов Иван Иванович'
This commit is contained in:
+60
-13
@@ -15,6 +15,62 @@ except ImportError:
|
||||
from .import_settings import load_settings, parse_cell_ref, cell_value
|
||||
|
||||
|
||||
# Известные аббревиатуры, которые сохраняются КАПСОМ при нормализации
|
||||
_CAPS_ABBR = {
|
||||
'АРМ', 'СКУД', 'СЗИ', 'СКЗИ', 'СОВ', 'ЛВС', 'ИНН', 'КПП', 'ОГРН', 'ЦОД',
|
||||
'МБУ', 'МКУ', 'ООО', 'СНИЛС', 'СБИС', 'ЕМСЭД', 'ФИО', 'ИСПДН', 'ККТ',
|
||||
}
|
||||
|
||||
|
||||
def _normalize_caps(text: str) -> str:
|
||||
"""Приводит КАПС-текст к нормальному регистру по словам.
|
||||
|
||||
Сохраняет:
|
||||
- аббревиатуры из белого списка (АРМ, СКУД, ООО, ИНН и т.п.)
|
||||
- инициалы и короткие служебные слова (И., Г., УЛ., №1)
|
||||
- числа и номера (350000, №1)
|
||||
- слова, уже содержащие строчные буквы
|
||||
Длинные слова целиком заглавными (ДИРЕКТОР, КРАСНОДАР, ПЕТРОВ) → «Директор», «Краснодар».
|
||||
"""
|
||||
words = text.split()
|
||||
result = []
|
||||
for w in words:
|
||||
# отделяем пунктуацию по краям слова
|
||||
pre = ''
|
||||
post = ''
|
||||
core = w
|
||||
while core and not core[0].isalnum():
|
||||
pre += core[0]
|
||||
core = core[1:]
|
||||
while core and not core[-1].isalnum():
|
||||
post = core[-1] + post
|
||||
core = core[:-1]
|
||||
if not core:
|
||||
result.append(w)
|
||||
continue
|
||||
# в слове уже есть строчные буквы — не трогаем
|
||||
if any('а' <= c <= 'я' or c == 'ё' for c in core):
|
||||
result.append(w)
|
||||
continue
|
||||
# нет заглавных кириллических букв (числа, латиница и т.п.) — не трогаем
|
||||
if not any('А' <= c <= 'Я' or c == 'Ё' for c in core):
|
||||
result.append(w)
|
||||
continue
|
||||
letters = [c for c in core if c.isalpha()]
|
||||
# инициалы и служебные слова (1-2 буквы: И., Г., УЛ., ООО — но ООО в белом списке)
|
||||
if len(letters) <= 2:
|
||||
result.append(w)
|
||||
continue
|
||||
# известная аббревиатура — сохраняем как есть
|
||||
if core.upper() in _CAPS_ABBR:
|
||||
result.append(w)
|
||||
continue
|
||||
# обычное длинное слово: первая заглавная, остальные строчные
|
||||
normalized = core[0].upper() + core[1:].lower()
|
||||
result.append(pre + normalized + post)
|
||||
return ' '.join(result)
|
||||
|
||||
|
||||
def clean_value(val):
|
||||
"""Очистка и нормализация значения ячейки Excel."""
|
||||
if val is None:
|
||||
@@ -33,20 +89,11 @@ def clean_value(val):
|
||||
text = str(val).strip()
|
||||
text = text.replace('\n', ' ').replace('\r', ' ')
|
||||
text = ' '.join(text.split())
|
||||
# Приведение регистра: если текст содержит только заглавные буквы РУ
|
||||
# НО не трогаем аббревиатуры/номера (АРМ №1, ИС, ЕМСЭД, СКУД и т.п.)
|
||||
if len(text) > 4 and any('А' <= c <= 'Я' or c == 'Ё' for c in text):
|
||||
# Если весь текст КАПСОМ (нет строчных букв) — нормализуем по словам
|
||||
if len(text) > 2 and any('А' <= c <= 'Я' or c == 'Ё' for c in text):
|
||||
has_lower = any('а' <= c <= 'я' or c == 'ё' for c in text)
|
||||
has_digit_or_num = bool(re.search(r'[0-9№«»"\']', text))
|
||||
if not has_lower and not has_digit_or_num:
|
||||
words = text.split()
|
||||
# если есть короткая аббревиатура целиком заглавными — не трогаем
|
||||
has_abbr = any(len(w) <= 4 and w.isupper() and any('А' <= c <= 'Я' for c in w) for w in words)
|
||||
if not has_abbr:
|
||||
if len(words) >= 3:
|
||||
text = text.title()
|
||||
else:
|
||||
text = text.capitalize()
|
||||
if not has_lower:
|
||||
text = _normalize_caps(text)
|
||||
return text
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user