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


import os
import re
import shutil
from pathlib import Path

# === НАСТРОЙКИ ===
# Укажи путь к главной папке (например, где лежит "1 ТФ" или все выгрузки)
SOURCE_DIR = Path(r"C:\Путь\к\твоей\исходной\папке")

# Папка, куда сложатся готовые красивые папки (создастся автоматически)
OUTPUT_DIR = Path(r"C:\Путь\к\папке\Итог_2023")

YEAR = "2023"

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

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


def process_profile_Content(profile_dir: Path):
    """Обрабатывает внутренние папки профиля (1 Описание ОП, 3 РПД и т.д.)"""
    for item in list(profile_dir.iterdir()):
        if not item.is_dir():
            continue

        # Получаем список всех элементов внутри подпапки (игнорируя скрытые системные файлы)
        contents = [
            x for x in item.iterdir() 
            if x.name.lower() not in ("thumbs.db", ".ds_store", "desktop.ini")
        ]
        files = [x for x in contents if x.is_file()]
        subdirs = [x for x in contents if x.is_dir()]

        # 1. Если папка вообще пустая — удаляем
        if len(files) == 0 and len(subdirs) == 0:
            item.rmdir()
            print(f"  [Удалена пустая папка] {item.name}")

        # 2. Если внутри ровно 1 файл и нет подпапок — выносим файл в корень профиля, папку удаляем
        elif len(files) == 1 and len(subdirs) == 0:
            single_file = files[0]
            target_path = profile_dir / single_file.name

            # Защита от перезаписи, если файл с таким именем уже есть в корне
            counter = 1
            while target_path.exists():
                target_path = profile_dir / f"{single_file.stem}_{counter}{single_file.suffix}"
                counter += 1

            shutil.move(str(single_file), str(target_path))
            shutil.rmtree(item)  # Удаляем опустевшую папку
            print(f"  [Файл вынесен] {single_file.name} (из '{item.name}')")

        # 3. Если файлов больше одного (или есть подпапки) — убираем номер из названия папки
        else:
            clean_name = LEADING_NUM_REGEX.sub("", item.name).strip()
            if clean_name and clean_name != item.name:
                target_dir = profile_dir / clean_name

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


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

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

    # Ищем все папки в глубине, которые начинаются с кода ОП (например, 54.03.01)
    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)  # Достаем только код, например "54.03.01"

            # Внутри папки направления лежат папки профилей ("Транспортный и промышленный дизайн")
            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, чтобы os.walk не шел глубже внутрь уже обработанных профилей
            dirs.clear()

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


if __name__ == "__main__":
    main()