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
|
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):
|
def clean_value(val):
|
||||||
"""Очистка и нормализация значения ячейки Excel."""
|
"""Очистка и нормализация значения ячейки Excel."""
|
||||||
if val is None:
|
if val is None:
|
||||||
@@ -33,20 +89,11 @@ def clean_value(val):
|
|||||||
text = str(val).strip()
|
text = str(val).strip()
|
||||||
text = text.replace('\n', ' ').replace('\r', ' ')
|
text = text.replace('\n', ' ').replace('\r', ' ')
|
||||||
text = ' '.join(text.split())
|
text = ' '.join(text.split())
|
||||||
# Приведение регистра: если текст содержит только заглавные буквы РУ
|
# Если весь текст КАПСОМ (нет строчных букв) — нормализуем по словам
|
||||||
# НО не трогаем аббревиатуры/номера (АРМ №1, ИС, ЕМСЭД, СКУД и т.п.)
|
if len(text) > 2 and any('А' <= c <= 'Я' or c == 'Ё' for c in text):
|
||||||
if len(text) > 4 and any('А' <= c <= 'Я' or c == 'Ё' for c in text):
|
|
||||||
has_lower = 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:
|
||||||
if not has_lower and not has_digit_or_num:
|
text = _normalize_caps(text)
|
||||||
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()
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user