خانه / آموزش‌ها / آموزش جامع ماژول difflib در پایتون (مقایسه متن و لیست)

آموزش جامع ماژول difflib در پایتون (مقایسه متن و لیست)

🐍 HomeOfPython
|
📅 1404/10/17

کتابخانه difflib یکی از ماژول‌های استاندارد و قدرتمند پایتون است که برای مقایسه توالی‌ها (Sequences) مانند رشته‌های متنی، لیست‌ها و فایل‌ها استفاده می‌شود. اگر تا به حال خواسته‌اید سیستمی بسازید که "آیا منظور شما این بود؟" (Did you mean) را پیاده‌سازی کند یا تفاوت بین دو فایل متنی را پیدا کند، difflib ابزار شماست.

در این مقاله، از مفاهیم اولیه مانند پیدا کردن کلمات مشابه شروع کرده و تا تولید گزارش‌های حرفه‌ای HTML و تحلیل دقیق Opcodes پیش می‌رویم.

ساختار مقایسه در دیف‌لیب

سطح مقدماتی (Beginner Level)

در این بخش با توابع کلیدی و پرکاربرد difflib که برای کارهای روزمره و ساده مناسب هستند آشنا می‌شویم.

۱. پیدا کردن موارد مشابه (get_close_matches)

یکی از محبوب‌ترین توابع این ماژول get_close_matches است. این تابع به شما کمک می‌کند تا نزدیک‌ترین رشته‌ها به یک رشته خاص را از بین یک لیست پیدا کنید. این اساس کار سیستم‌های اصلاح غلط املایی است.

مثال اول: اصلاح غلط املایی ساده

فرض کنید کاربر کلمه "appel" را وارد کرده و ما می‌خواهیم حدس بزنیم منظورش چه بوده است.

Python

مثال دوم: تنظیم حساسیت و تعداد نتایج

شما می‌توانید با پارامترهای n (تعداد نتایج) و cutoff (حداقل درصد شباهت بین ۰ تا ۱) نتایج را فیلتر کنید.

Python

۲. محاسبه درصد شباهت (SequenceMatcher)

کلاس SequenceMatcher قلب تپنده این ماژول است. این کلاس می‌تواند دو توالی را مقایسه کرده و یک عدد بین 0.0 (کاملا متفاوت) تا 1.0 (کاملا یکسان) به عنوان نسبت شباهت برگرداند.

مثال اول: شباهت دو رشته متنی

Python

مثال دوم: مقایسه لیست اعداد

difflib فقط مختص متن نیست؛ هر نوع توالی (Sequence) قابل هش (Hashable) را مقایسه می‌کند.

Python

۳. نمایش تفاوت‌ها به صورت خط به خط (Differ)

کلاس Differ برای تولید تفاوت‌ها به صورتی که برای انسان خوانا باشد (Human-readable) استفاده می‌شود. خروجی شبیه به دستور diff در لینوکس است.

  • -: خطی که در متن اول بوده ولی در دوم نیست.
  • +: خطی که در متن دوم اضافه شده است.
  • : خطی که در هر دو مشترک است.

مثال اول: مقایسه متن چند خطی

Python

مثال دوم: مقایسه درون خطی (Intraline diff)

کلاس Differ گاهی اوقات کاراکتر ^ را نشان می‌دهد تا دقیقاً مشخص کند تغییر در کجای خط رخ داده است.

Python

سطح پیشرفته (Professional Level)

در این بخش به سراغ تولید گزارش‌های استاندارد، خروجی HTML برای وب‌سایت‌ها، و درک عمیق الگوریتم‌های تطبیق (Matching Algorithms) می‌رویم.

۱. تولید گزارش تفاوت HTML (HtmlDiff)

برای نمایش تفاوت‌ها در وب‌سایت یا داشبوردهای مدیریتی، بهترین گزینه HtmlDiff است. این کلاس یک جدول کامل HTML شامل رنگ‌بندی تفاوت‌ها تولید می‌کند.

مثال اول: ساخت جدول مقایسه کامل

Python

مثال دوم: شخصی‌سازی جدول HTML

شما می‌توانید تب‌ها را به فاصله تبدیل کنید یا از حالت make_table برای گرفتن فقط تگ

(بدون و کامل) استفاده کنید تا آن را در قالب سایت خود قرار دهید.

python
# Static Snippet: Function signature for customization
# این کد استاتیک است چون فقط نشان‌دهنده نحوه فراخوانی متد است
html_diff = difflib.HtmlDiff(tabsize=4, wrapcolumn=60)
table_only = html_diff.make_table(lines1, lines2)

۲. فرمت‌های استاندارد Unified و Context Diff

در ابزارهای کنترل نسخه (مانند Git) یا پچ کردن فایل‌ها، فرمت‌های خاصی استاندارد هستند. difflib این فرمت‌ها را پشتیبانی می‌کند.

مثال اول: Unified Diff (فرمت فشرده)

این فرمت بسیار محبوب است و فقط خطوط تغییر یافته به همراه چند خط زمینه (Context) را نشان می‌دهد.

Python

مثال دوم: Context Diff

این فرمت قدیمی‌تر است و دو فایل را جداگانه با علامت‌گذاری تغییرات نشان می‌دهد.

Python

۳. تحلیل عمیق با Opcodes

اگر نیاز دارید دقیقاً بدانید چه عملیاتی (حذف، درج، جایگزینی) باید انجام شود تا لیست A به لیست B تبدیل شود، باید از متد get_opcodes() در SequenceMatcher استفاده کنید.

خروجی این متد شامل تاپل‌هایی به فرمت (tag, i1, i2, j1, j2) است:

  • replace: a[i1:i2] باید با b[j1:j2] جایگزین شود.
  • delete: a[i1:i2] باید حذف شود.
  • insert: b[j1:j2] باید در موقعیت i1 در a درج شود.
  • equal: این بخش‌ها یکسان هستند.

مثال اول: استخراج عملیات تغییر

Python

مثال دوم: پیدا کردن طولانی‌ترین بخش مشترک

متد find_longest_match برای پیدا کردن بزرگترین زیررشته مشترک استفاده می‌شود که در الگوریتم‌های فشرده‌سازی متن کاربرد دارد.

Python

۴. فیلتر کردن نویزها (Junk Elements)

در مقایسه فایل‌های کد منبع، گاهی اوقات می‌خواهیم فاصله‌های خالی (Whitespace) یا خطوط خالی را نادیده بگیریم. پارامتر اول SequenceMatcher (که معمولا None است) تابعی است که مشخص می‌کند چه کاراکترهایی "Junk" هستند.

مثال اول: نادیده گرفتن فاصله‌ها

در این مثال، اگر فاصله را نادیده نگیریم، رشته‌ها متفاوتند، اما با نادیده گرفتن فاصله، الگوریتم رفتار متفاوتی در محاسبه بلوک‌ها نشان می‌دهد (هرچند ratio() کلی تغییر چندانی نمی‌کند، اما نحوه تطبیق بلوک‌ها عوض می‌شود). الگوریتم difflib به این صورت است که Junkها را در تطبیق بلوک‌ها شرکت نمی‌دهد.

Python

مثال دوم: بهینه‌سازی سرعت با autojunk

زمانی که لیست‌های بسیار بزرگ را مقایسه می‌کنید، اگر عنصری بیش از ۱٪ کل لیست تکرار شده باشد، difflib به صورت خودکار آن را نادیده می‌گیرد تا سرعت بالا رود. می‌توانید با autojunk=False این قابلیت را خاموش کنید.

python
# Static: نمایش پارامتر در سازنده
# استفاده از autojunk برای لیست‌های بزرگ توصیه می‌شود
matcher = difflib.SequenceMatcher(None, large_list_a, large_list_b, autojunk=True)