fix: импорт средств защиты — каждая программа отдельным средством

Проблема: clean_value заменял переносы строк на пробелы, из-за чего
список программ в одной ячейке (каждая с новой строки) склеивался
в одну строку. Теперь сырые значения ячеек сохраняются (raw_rows),
разбивка по \n/;/, названия не режутся (KES ≠ KSC).
This commit is contained in:
2026-08-04 15:46:34 +04:00
parent 4e7c3463f4
commit 9489e6a37d
+31 -16
View File
@@ -268,12 +268,15 @@ def _import_187_is_list(wb, data, settings, log_fn):
for sheet_name in is_sheets:
ws = wb[sheet_name]
rows = []
raw_rows = []
for row in ws.iter_rows(min_row=1, values_only=True):
raw_vals = list(row)
vals = [clean_value(c) for c in row]
field = (vals[0] or '').strip() if vals else ''
if not field:
continue
rows.append(vals)
raw_rows.append(raw_vals)
if len(rows) < 2:
continue
@@ -313,28 +316,40 @@ def _import_187_is_list(wb, data, settings, log_fn):
return False
def _split_entries(text):
"""Разбивает слипшиеся названия СЗИ: по переносам строк, ';' и по границе
'цифра + заглавная буква' (напр. '15.1.0.22239Kaspersky' → два названия)."""
if not text:
"""Разбивает список средств защиты на ОТДЕЛЬНЫЕ программы.
В опроснике каждая программа записана с новой строки (разделитель \n),
также поддерживаются ';' и ','. Название программы при этом НЕ режется
(напр. 'Kaspersky Endpoint Security' остаётся одним средством, KES ≠ KSC).
"""
if text is None:
return []
parts = re.split(r'[\n;]+', text)
# 1) разбиваем по переносам строк и ';'
parts = re.split(r'[\n\r;]+', str(text))
out = []
for p in parts:
p = p.strip()
if not p:
continue
# граница: цифра/точка → заглавная буква без пробела
sub = re.split(r'(?<=[0-9.])(?=[А-ЯЁA-Z])', p)
for s in sub:
s = s.strip()
if s and s not in out:
out.append(s)
# 2) дополнительно по запятой (если список через запятую)
for sub in re.split(r'\s*,\s*', p):
sub = sub.strip()
if not sub:
continue
# 3) запасной вариант: слипшиеся без разделителя «15.1.0.22239Kaspersky»
sub_parts = re.split(r'(?<=[0-9.])(?=[А-ЯЁA-Z])', sub)
for s in sub_parts:
s = s.strip()
if not s:
continue
cleaned = clean_value(s)
if cleaned and cleaned not in out:
out.append(cleaned)
return out
for vals in rows:
for idx, vals in enumerate(rows):
field = (vals[0] or '').strip()
field_lower = field.lower()
val_b = clean_value(vals[1]) if len(vals) > 1 else ''
raw_row = raw_rows[idx] if idx < len(raw_rows) else vals
raw_b = raw_row[1] if len(raw_row) > 1 else None # сырое значение (с переносами строк!)
val_b = clean_value(raw_b) if raw_b is not None else ''
is_checked = val_b.upper() in ('ДА', 'YES', '', '', '1', 'TRUE', 'ЕСТЬ')
# --- Наименование объекта ---
@@ -479,7 +494,7 @@ def _import_187_is_list(wb, data, settings, log_fn):
for kw, label in defense_keywords.items():
if re.search(kw, field_lower):
if val_b and 'выбрать' not in field_lower:
for tool in _split_entries(val_b):
for tool in _split_entries(raw_b if raw_b is not None else val_b):
if tool not in is_obj['defense_tools']:
is_obj['defense_tools'].append(tool)
matched = True