شارك المقالة

سكريبت Python لتحويل أسماء الملفات إلى حروف صغيرة lower case وإزالة المسافات

عند التعامل مع عدد كبير من الملفات قد تجد أن أسماء الملفات غير منظمة، فبعضها يحتوي على حروف كبيرة ومسافات وشرطات ورموز مختلفة مثل:

My File (1).JPG
REPORT-Final.PDF
data SET .csv

وقد تصبح إعادة تسمية عشرات أو مئات الملفات يدويًا عملية مزعجة وتحتاج إلى الكثير من الوقت، لذلك يمكن استخدام Python لإنشاء سكريبت يقوم بإعادة تسمية جميع الملفات بشكل تلقائي.

في هذا المقال سنتعرف على كيفية إنشاء سكريبت Python يقوم بتحويل أسماء الملفات إلى حروف صغيرة lower case، وإزالة المسافات والشرطات، وتوحيد امتدادات الملفات، بالإضافة إلى التعامل مع الملفات التي تحتوي على أسماء متكررة.

لماذا نحتاج إلى توحيد أسماء الملفات؟

توحيد أسماء الملفات يساعد على تنظيم الملفات والتعامل معها بشكل أفضل، خصوصًا عند وجود عدد كبير من الملفات داخل نفس المجلد.

ومن أهم فوائد توحيد أسماء الملفات:

  • تسهيل البحث عن الملفات.
  • تنظيم الملفات بشكل أفضل.
  • تقليل المشاكل الناتجة عن اختلاف حالة الأحرف.
  • تسهيل التعامل مع الملفات من خلال أوامر Terminal وShell.
  • تحسين التعامل مع السكريبتات والبرامج التي تعتمد على أسماء الملفات.
  • تسهيل رفع الملفات ومزامنتها مع الخدمات السحابية.

أخطاء شائعة عند إعادة تسمية الملفات باستخدام Python

قد يبدو كود إعادة تسمية الملفات بسيطًا، ولكن هناك بعض الأخطاء التي يجب الانتباه إليها عند التعامل مع أسماء الملفات والامتدادات.

على سبيل المثال، الدالة os.path.splitext() تقوم بفصل اسم الملف عن امتداده.

old_name, extension = os.path.splitext(f)

فإذا كان اسم الملف:

My File.JPG

فسيكون الناتج تقريبًا:

old_name = "My File"
extension = ".JPG"

وبالتالي يمكننا تعديل اسم الملف بدون التأثير على الامتداد.

استبدال المسافات برمز غير صالح

من الأخطاء التي قد تحدث استخدام الرمز * بدلًا من المسافات، مثل:

replace(" ", "*")

وهذا غير مناسب لأن بعض الرموز مثل * تعتبر غير صالحة في أسماء الملفات على نظام Windows.

والأفضل استبدال المسافات بالشرطة السفلية _:

replace(" ", "_")

حذف آخر حرف من اسم الملف

استخدام [:-1] يؤدي إلى حذف آخر حرف من النص، وبالتالي قد يتم حذف جزء من اسم الملف بدون قصد.

فعلى سبيل المثال:

report

سيصبح:

repor

لذلك لا يجب استخدام هذه الطريقة إلا إذا كان حذف آخر حرف من الاسم أمرًا مقصودًا.

إضافة مسافة بدل النقطة قبل الامتداد

يجب أن يكون اسم الملف بالشكل التالي:

report.pdf

وليس:

report .pdf

لذلك من الأفضل الاحتفاظ بالامتداد الذي تقوم os.path.splitext() بإرجاعه واستخدامه مباشرة عند إنشاء الاسم الجديد.

سكريبت Python بسيط لإعادة تسمية الملفات

إذا كنت تريد سكريبت بسيط يقوم بتحويل أسماء الملفات إلى حروف صغيرة lower case واستبدال المسافات والشرطات بالشرطة السفلية، يمكنك استخدام الكود التالي:

import os

os.chdir(r"######path######")

for f in os.listdir():
    old_name, extension = os.path.splitext(f)

    # تحويل الاسم إلى حروف صغيرة
    new_name = old_name.lower()

    # استبدال المسافات والشرطات بـ _
    new_name = new_name.replace(" ", "_")
    new_name = new_name.replace("-", "_")

    # تحويل الامتداد إلى حروف صغيرة lower case
    extension = extension.lower()

    new_name = new_name + extension

    os.rename(f, new_name)

يقوم هذا السكريبت بقراءة جميع الملفات الموجودة داخل المجلد، ثم تحويل اسم كل ملف إلى حروف صغيرة lower case واستبدال المسافات والشرطات بالشرطة السفلية _.

فمثلًا إذا كان اسم الملف:

My File-Report.JPG

فسيصبح:

my_file_report.jpg

ولكن هذه النسخة البسيطة لا تتعامل مع بعض الحالات المهمة مثل وجود ملف آخر يحمل الاسم الجديد نفسه، لذلك يمكن استخدام نسخة أكثر تطورًا.

سكريبت Python متقدم لإعادة تسمية الملفات

النسخة التالية توفر مجموعة من المميزات الإضافية التي تجعل عملية إعادة تسمية الملفات أكثر أمانًا ومرونة.

  • تحويل أسماء الملفات إلى حروف صغيرة .
  • إزالة المسافات الزائدة.
  • استبدال المسافات والشرطات بالشرطة السفلية.
  • إزالة الرموز غير الصالحة من أسماء الملفات.
  • تحويل امتدادات الملفات إلى حروف صغيرة.
  • التعامل مع الأسماء المتكررة.
  • دعم المجلدات الفرعية.
  • دعم وضع المعاينة Dry Run.
  • حفظ سجل بالتغييرات داخل ملف JSON.
import os
import re
from pathlib import Path
import json
from datetime import datetime


INVALID_CHARS = r'<>:"/\\|?*\0'


def sanitize(name: str) -> str:
    n = name.lower().strip()

    # استبدال المسافات والشرطات بـ _
    n = re.sub(r'[\s\-]+', '_', n)

    # إزالة الأحرف غير الصالحة
    n = re.sub(f'[{re.escape(INVALID_CHARS)}]', '', n)

    # إزالة النقاط من بداية ونهاية الاسم
    n = n.strip('.')

    # منع تكرار _
    n = re.sub(r'_+', '_', n)

    return n or "unnamed"


def unique_target(path: Path) -> Path:
    parent = path.parent
    base = path.stem
    ext = path.suffix

    candidate = path
    counter = 1

    while candidate.exists():
        candidate = parent / f"{base}_{counter}{ext}"
        counter += 1

    return candidate


def rename_folder(
    folder: str,
    recursive=False,
    dry_run=True,
    save_log=True
):
    folder_p = Path(folder)

    if not folder_p.exists():
        raise FileNotFoundError(folder)

    log = []

    targets = (
        folder_p.rglob("*")
        if recursive
        else folder_p.iterdir()
    )

    for p in targets:

        if p.is_file():

            new_stem = sanitize(p.stem)

            # تحويل الامتداد إلى lowercase
            new_name = new_stem + p.suffix.lower()

            dst = p.with_name(new_name)

            # التعامل مع الأسماء المتكررة
            if dst.exists() and dst != p:
                dst = unique_target(dst)

            if dst.name != p.name:

                log_entry = {
                    "from": str(p),
                    "to": str(dst),
                    "timestamp": datetime.utcnow().isoformat()
                }

                if dry_run:
                    print(f"[DRY] {p.name} -> {dst.name}")
                else:
                    print(f"{p.name} -> {dst.name}")
                    p.rename(dst)

                log.append(log_entry)

    if save_log and log:

        log_path = (
            folder_p /
            f"rename_log_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}.json"
        )

        with open(log_path, "w", encoding="utf-8") as f:
            json.dump(
                log,
                f,
                ensure_ascii=False,
                indent=2
            )

        print("Log saved to", log_path)


if __name__ == "__main__":

    import argparse

    parser = argparse.ArgumentParser()

    parser.add_argument(
        "path",
        help="Path to the folder"
    )

    parser.add_argument(
        "--execute",
        action="store_true",
        help="Apply changes (default is dry-run)"
    )

    parser.add_argument(
        "--recursive",
        action="store_true",
        help="Rename files recursively"
    )

    args = parser.parse_args()

    rename_folder(
        args.path,
        recursive=args.recursive,
        dry_run=not args.execute
    )

شرح دالة تنظيف اسم الملف

تعتبر دالة sanitize من أهم أجزاء السكريبت، حيث تقوم بتنظيف اسم الملف قبل استخدامه كاسم جديد.

def sanitize(name: str) -> str:
    n = name.lower().strip()

يقوم هذا الجزء بتحويل اسم الملف إلى حروف صغيرة lower case وإزالة المسافات الموجودة في بداية ونهاية الاسم.

بعد ذلك يتم استبدال المسافات والشرطات بالشرطة السفلية:

n = re.sub(r'[\s\-]+', '_', n)

فمثلًا:

My Important-File

سيصبح:

my_important_file

كما يقوم السكريبت بإزالة الرموز غير الصالحة من اسم الملف، ثم يمنع تكرار الشرطة السفلية.

التعامل مع الملفات التي تحمل الاسم نفسه

قد يحدث أن يؤدي تحويل أسماء الملفات إلى حروف صغيرة lower case إلى وجود أكثر من ملف يحمل الاسم نفسه.

على سبيل المثال:

Report.JPG
report.jpg

بعد تحويل الأسماء إلى حروف صغيرة سيصبح كلاهما:

report.jpg

ولحل هذه المشكلة يستخدم السكريبت الدالة unique_target لإنشاء اسم مختلف للملف بدلًا من الكتابة فوق الملف الموجود.

وبالتالي يمكن أن تصبح الأسماء:

report.jpg
report_1.jpg
report_2.jpg

استخدام Dry Run قبل تنفيذ التغييرات

من المميزات المهمة في السكريبت وجود وضع Dry Run، والذي يسمح لك بمشاهدة أسماء الملفات الجديدة قبل تنفيذ عملية إعادة التسمية فعليًا.

يمكن تشغيل السكريبت بدون الخيار –execute:

python robust_rename.py "/path/to/folder"

وسيظهر لك الناتج المتوقع مثل:

[DRY] My File.JPG -> my_file.jpg
[DRY] REPORT-Final.PDF -> report_final.pdf
[DRY] data SET.csv -> data_set.csv

وبذلك يمكنك مراجعة جميع التغييرات قبل تنفيذها على الملفات الأصلية.

تنفيذ إعادة تسمية الملفات فعليًا

بعد التأكد من أن الأسماء الجديدة مناسبة، يمكنك استخدام الخيار –execute لتنفيذ عملية إعادة التسمية.

python robust_rename.py "/path/to/folder" --execute

عند تشغيل السكريبت بهذا الخيار سيتم تطبيق التغييرات على الملفات الموجودة داخل المجلد.

إعادة تسمية الملفات داخل المجلدات الفرعية

إذا كان المجلد يحتوي على مجلدات فرعية وتريد تطبيق عملية إعادة التسمية على جميع الملفات الموجودة داخلها، يمكنك استخدام الخيار –recursive.

python robust_rename.py "/path/to/folder" --execute --recursive

وبذلك سيقوم السكريبت بالبحث داخل المجلد الرئيسي وجميع المجلدات الفرعية وإعادة تسمية الملفات الموجودة بداخلها.

حفظ سجل بالتغييرات

يقوم السكريبت أيضًا بإنشاء ملف JSON يحتوي على سجل بالملفات التي تم تغيير أسمائها.

ويحتوي السجل على الاسم القديم والاسم الجديد ووقت تنفيذ العملية، مما يساعدك على معرفة التغييرات التي تم إجراؤها.

[
    {
        "from": "My File.JPG",
        "to": "my_file.jpg",
        "timestamp": "2026-09-14T08:30:00"
    }
]

نصائح قبل تشغيل السكريبت

  • قم بأخذ نسخة احتياطية من المجلد قبل إعادة تسمية الملفات.
  • استخدم وضع Dry Run أولًا لمراجعة التغييرات.
  • جرب السكريبت على مجلد صغير قبل استخدامه على عدد كبير من الملفات.
  • تأكد من الملفات التي تحتوي على أسماء عربية أو أحرف Unicode.
  • انتبه عند التعامل مع الملفات المخفية مثل .env و .gitignore.
  • تأكد من أن البرامج الأخرى التي تستخدم الملفات تستطيع التعامل مع الأسماء الجديدة.

الخلاصة

يمكن استخدام Python لأتمتة الكثير من المهام المتكررة، ومن بينها إعادة تسمية عدد كبير من الملفات داخل مجلد.

ومن خلال السكريبت السابق يمكنك تحويل أسماء الملفات إلى حروف صغيرة، وإزالة المسافات والشرطات، وتوحيد امتدادات الملفات، بالإضافة إلى التعامل مع الأسماء المتكررة والمجلدات الفرعية.

ويفضل دائمًا استخدام Dry Run أولًا ومراجعة النتائج قبل تنفيذ التغييرات، خصوصًا عند التعامل مع عدد كبير من الملفات المهمة.



مزيد من المقالات :
شرح Scrapy في Python 3 لاستخراج الصور من Google Drive الاسم والرابط بصيغة JSON بسهولة
شرح مكتبة Safe Image لفلترة الصور الحساسة بالذكاء الاصطناعي
شاهد أيضًا
مقالات ذات صلة

🚫 مانع الإعلانات مفعل

يجب إيقاف مانع الإعلانات لاستكمال تصفح الموقع