Загрузка данных


import os
import re
import shutil
from pathlib import Path

# === НАСТРОЙКИ ===
SOURCE_DIR = Path(r"C:\Путь\к\твоей\исходной\папке")
OUTPUT_DIR = Path(r"C:\Путь\к\папке\Итог_2023")

YEAR = "2023"

# Список папок, которые нужно ОСТАВИТЬ (в нижнем регистре для надежного сравнения)
KEEP_FOLDERS = {
    "мр и др": "МР и др",
    "мр и др.": "МР и др",
    "рпд": "РПД",
    "рпп": "РПП"
}

# Регулярка для поиска кода направления (например, "54.03.01 Дизайн")
OP_CODE_REGEX = re.compile(r"^(\d{2}\.\d{2}\.\d{2})\b")

# Регулярка для удаления цифр в начале папок ("3 РПД" -> "РПД")
LEADING_NUM_REGEX = re.compile(r"^\d+[\.\s_-]*")


def move_file_safely(src_file: Path, target_dir: Path):
    """Перемещает файл в нужную папку, добавляя счетчик, если имя уже занято."""
    target_path = target_dir / src_file.name
    counter = 1
    while target_path.exists():
        target_path = target_dir / f"{src_file.stem}_{counter}{src_file.suffix}"
        counter += 1
    shutil.move(str(src_file), str(target_path))


def process_profile_content(profile_dir: Path):
    """Оставляет только МР и др, РПД, РПП, а из остальных выносит файлы в корень."""
    for item in list(profile_dir.iterdir()):
        if not item.is_dir():
            continue

        # Убираем номер в начале названия ("8 МР и др" -> "МР и др")
        clean_name = LEADING_NUM_REGEX.sub("", item.name).strip()
        clean_name_lower = clean_name.lower()

        # 1. Если это одна из 3 папок, которые нужно оставить
        if clean_name_lower in KEEP_FOLDERS:
            standard_name = KEEP_FOLDERS[clean_name_lower]
            target_dir = profile_dir / standard_name

            if item != target_dir:
                if not target_dir.exists():
                    item.rename(target_dir)
                    print(f"  [Переименована] '{item.name}' -> '{standard_name}'")
                else:
                    # Если папка уже есть, сливаем содержимое в неё
                    for sub_item in item.iterdir():
                        if sub_item.is_file():
                            move_file_safely(sub_item, target_dir)
                        elif sub_item.is_dir():
                            shutil.move(str(sub_item), str(target_dir / sub_item.name))
                    shutil.rmtree(item)
                    print(f"  [Объединена] '{item.name}' -> '{standard_name}'")

        # 2. Все остальные папки (Описание ОП, АУП, Анн РПД, Графики УП и т.д.)
        else:
            files_moved = 0
            # rglob("*") достанет все файлы, даже если внутри были еще подпапки
            for sub_item in item.rglob("*"):
                if sub_item.is_file() and sub_item.name.lower() not in ("thumbs.db", ".ds_store", "desktop.ini"):
                    move_file_safely(sub_item, profile_dir)
                    files_moved += 1

            # Удаляем саму папку после выноса файлов
            shutil.rmtree(item)
            print(f"  [Распакована и удалена] '{item.name}' (вынесено файлов: {files_moved})")


def main():
    if not SOURCE_DIR.exists():
        print(f"Ошибка: Исходная папка {SOURCE_DIR} не найдена!")
        return

    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

    for root, dirs, _ in os.walk(SOURCE_DIR):
        root_path = Path(root)
        match = OP_CODE_REGEX.match(root_path.name)

        if match:
            op_code = match.group(1)

            for profile_dir in root_path.iterdir():
                if profile_dir.is_dir():
                    profile_name = profile_dir.name.strip()
                    new_folder_name = f"{YEAR} {op_code} {profile_name}"
                    target_profile_path = OUTPUT_DIR / new_folder_name

                    print(f"\nОбработка: {new_folder_name}")

                    if target_profile_path.exists():
                        shutil.rmtree(target_profile_path)
                    shutil.copytree(profile_dir, target_profile_path)

                    process_profile_content(target_profile_path)

            dirs.clear()

    print("\nГотово! Все папки собраны в:", OUTPUT_DIR)


if __name__ == "__main__":
    main()