Загрузка данных
from pathlib import Path
import re
from copy import copy
from openpyxl import load_workbook
# ====== Настройки ======
SOURCE_FILE = Path(r"C:\path\to\first.xlsx") # Первая книга: лист «Лист1»
TARGET_FILE = Path(r"C:\path\to\second.xlsx") # Вторая книга: лист «Вся База»
OUTPUT_FILE = Path(r"C:\path\to\second_filled.xlsx")
SOURCE_SHEET = "Лист1"
TARGET_SHEET = "Вся База"
# Номера столбцов: A=1, B=2, M=13, AE=31, AF=32, AG=33
COL_SOURCE_A = 1
COL_SOURCE_B = 2
COL_SOURCE_M = 13
COL_TARGET_AE = 31
COL_TARGET_AF = 32
COL_TARGET_AG = 33
# Вставьте сюда вашу уже существующую логику обработки идентификатора M.
def normalize_identifier_from_need(col_m_value):
"""Преобразует идентификатор из M к виду, используемому для поиска в AE.
Ниже — безопасный пример: строка, удаление пробелов, верхний регистр.
Замените тело функции на ваш фактический маленький скрипт, если он иной.
"""
if col_m_value is None:
return None
short_id = str(col_m_value).strip()
if not short_id:
return None
short_id = re.sub(r"\s+", "", short_id).upper()
return short_id
def as_excel_text(value):
"""Возвращает значение как текст, без превращения номера заявки в число."""
if value is None:
return ""
return str(value).strip()
def main():
if not SOURCE_FILE.exists():
raise FileNotFoundError(f"Не найден исходный файл: {SOURCE_FILE}")
if not TARGET_FILE.exists():
raise FileNotFoundError(f"Не найден целевой файл: {TARGET_FILE}")
# data_only=False важен, если в ячейках есть формулы и нужно читать сами формулы.
wb_source = load_workbook(SOURCE_FILE, read_only=True, data_only=False)
wb_target = load_workbook(TARGET_FILE)
if SOURCE_SHEET not in wb_source.sheetnames:
raise ValueError(f"В первой книге нет листа «{SOURCE_SHEET}»")
if TARGET_SHEET not in wb_target.sheetnames:
raise ValueError(f"Во второй книге нет листа «{TARGET_SHEET}»")
ws_source = wb_source[SOURCE_SHEET]
ws_target = wb_target[TARGET_SHEET]
# Индекс: нормализованный идентификатор из AE -> список строк во второй книге.
# Список, а не одна строка: так не пропадут данные при дублях в AE.
target_index = {}
for row in range(1, ws_target.max_row + 1):
raw_ae = ws_target.cell(row=row, column=COL_TARGET_AE).value
normalized_ae = normalize_identifier_from_need(raw_ae)
if normalized_ae:
target_index.setdefault(normalized_ae, []).append(row)
processed = 0
matched_source_rows = 0
updated_cells = 0
empty_identifier_rows = []
not_found = []
duplicate_matches = []
# Предполагается, что первая строка содержит заголовки.
for source_row in range(2, ws_source.max_row + 1):
processed += 1
value_a = as_excel_text(ws_source.cell(source_row, COL_SOURCE_A).value)
value_b = as_excel_text(ws_source.cell(source_row, COL_SOURCE_B).value)
raw_m = ws_source.cell(source_row, COL_SOURCE_M).value
short_id = normalize_identifier_from_need(raw_m)
if not short_id:
empty_identifier_rows.append(source_row)
continue
target_rows = target_index.get(short_id, [])
if not target_rows:
not_found.append((source_row, short_id))
continue
matched_source_rows += 1
if len(target_rows) > 1:
duplicate_matches.append((source_row, short_id, target_rows))
# Если во второй книге найдено несколько строк с одним идентификатором,
# значения переносятся во все найденные строки.
for target_row in target_rows:
cell_af = ws_target.cell(target_row, COL_TARGET_AF)
cell_ag = ws_target.cell(target_row, COL_TARGET_AG)
# Формат Text, чтобы Excel не потерял ведущие нули и не представил длинные номера как число.
cell_af.number_format = "@"
cell_ag.number_format = "@"
cell_af.value = value_a
cell_ag.value = value_b
updated_cells += 2
wb_target.save(OUTPUT_FILE)
wb_source.close()
wb_target.close()
print(f"Готово. Результат сохранён: {OUTPUT_FILE}")
print(f"Проверено строк в «{SOURCE_SHEET}»: {processed}")
print(f"Строк первой книги с совпадением в AE: {matched_source_rows}")
print(f"Записано ячеек AF/AG: {updated_cells}")
print(f"Пустой или некорректный M: {len(empty_identifier_rows)}")
print(f"Идентификатор не найден в AE: {len(not_found)}")
print(f"Совпадений с дублями в AE: {len(duplicate_matches)}")
if not_found:
print("\nПервые 20 не найденных идентификаторов (строка Лист1, идентификатор):")
for item in not_found[:20]:
print(item)
if duplicate_matches:
print("\nПервые 20 идентификаторов с несколькими строками в AE:")
for item in duplicate_matches[:20]:
print(item)
if __name__ == "__main__":
main()