ToolDeck

مقایسه‌گر متن

دو متن را کنار یکدیگر مقایسه کنید و تفاوت‌ها را خط‌به‌خط برجسته کنید

یک مثال امتحان کنید

متن الف

متن ب

به‌صورت محلی اجرا می‌شود · جای‌گذاری اسرار امن است
به‌صورت محلی اجرا می‌شود · جای‌گذاری اسرار امن است

مقایسه متن (Text Diff) چیست؟

مقایسه متن (Text Diff) نتیجه مقایسه دو بلوک متن و شناسایی خط‌هایی است که اضافه، حذف، یا بدون تغییر مانده‌اند. این مفهوم از ابزار diff در Unix گرفته شده که در سال ۱۹۷۴ به عنوان بخشی از Version 5 Unix منتشر شد. امروزه، مقایسه متن ستون فقرات سیستم‌های کنترل نسخه مانند Git است، جایی که هر commit یک diff ذخیره می‌کند نه یک نسخه کامل از هر فایل.

یک الگوریتم diff طولانی‌ترین زیردنباله مشترک (LCS) بین دو دنباله از خطوط را پیدا می‌کند. خطوطی که در LCS وجود دارند به عنوان بدون تغییر علامت‌گذاری می‌شوند. خطوطی که در متن اصلی هستند اما در LCS نیستند به عنوان حذف‌شده علامت‌گذاری می‌شوند. خطوطی که در متن ویرایش‌شده هستند اما در LCS نیستند به عنوان افزوده‌شده علامت‌گذاری می‌شوند. نتیجه حداقل مجموعه تغییرات لازم برای تبدیل یک متن به دیگری است.

خروجی diff در چند قالب ارائه می‌شود. unified diff (پیش‌فرض برای git diff) خطوط حذف‌شده را با علامت منفی و خطوط افزوده‌شده را با علامت مثبت مشخص می‌کند. side-by-side diff هر دو متن را در ستون‌های موازی قرار می‌دهد. این ابزار از مقایسه خط‌به‌خط با رنگ‌بندی استفاده می‌کند: سبز برای افزوده‌شده‌ها، قرمز برای حذف‌شده‌ها، و خنثی برای خطوط بدون تغییر. خطوط بدون تغییر به‌طور پیش‌فرض بدون پیشوند نمایش داده می‌شوند اما می‌توان آن‌ها را پنهان کرد تا تنها روی تغییرات تمرکز شود.

چرا از ابزار مقایسه متن آنلاین استفاده کنیم؟

مقایسه متن در ترمینال نیاز به نصب ابزارهای diff و کار با flag‌های خط فرمان دارد. یک ابزار diff مبتنی بر مرورگر این اصطکاک را به‌طور کامل از بین می‌برد.

مقایسه فوری
دو بلوک متن را بچسبانید و تفاوت‌ها را فوراً برجسته‌شده ببینید. بدون ایجاد فایل، بدون دستوری که باید به خاطر بسپارید، بدون خروجی برای تجزیه.
🔒
پردازش با اولویت حریم خصوصی
تمام مقایسه‌ها در مرورگر شما با استفاده از JavaScript انجام می‌شود. متن شما هرگز از دستگاه‌تان خارج نمی‌شود، که هنگام مقایسه فایل‌های پیکربندی، اعتبارنامه‌ها، یا کد اختصاصی اهمیت دارد.
📋
خروجی آماده برای کپی
خروجی diff از پیشوندهای استاندارد + / - استفاده می‌کند که با قالب unified diff مطابقت دارند. می‌توانید نتیجه را مستقیماً در پیام‌های commit، نظرات بازبینی کد، یا گزارش‌های اشکال کپی کنید.
🌐
بدون نیاز به ورود یا نصب
روی هر دستگاهی با مرورگر کار می‌کند. بدون ایجاد حساب کاربری، بدون افزونه، بدون برنامه دسکتاپ. صفحه را باز کنید و شروع به مقایسه کنید.

موارد استفاده از ابزار مقایسه متن

توسعه فرانت‌اند
خروجی CSS یا HTML فشرده‌شده را قبل و بعد از یک مرحله build مقایسه کنید تا تغییرات ناخواسته در markup یا استایل‌های تولیدشده را شناسایی کنید.
مهندسی بک‌اند
پاسخ‌های API را در محیط‌های مختلف (staging در مقابل production) مقایسه کنید تا تأیید کنید که یک استقرار تغییرات داده‌ای غیرمنتظره‌ای ایجاد نکرده است.
DevOps و زیرساخت
مانیفست‌های Kubernetes، پلن‌های Terraform، یا تنظیمات Nginx را قبل از اعمال تغییرات به یک cluster یا سرور زنده مقایسه کنید.
QA و آزمون
تأیید کنید که خروجی آزمون با خطوط پایه مورد انتظار مطابقت دارد با مقایسه نتیجه واقعی در برابر یک فایل snapshot ذخیره‌شده.
مهندسی داده
سرصفحه‌های CSV یا تعریف‌های schema پایگاه داده SQL را در طول مهاجرت‌های پایگاه داده مقایسه کنید تا تأیید کنید ستون‌ها به‌درستی اضافه یا تغییر نام یافته‌اند.
یادگیری و دوره‌های آموزشی
راه‌حل خود را خط‌به‌خط با یک پیاده‌سازی مرجع مقایسه کنید تا ببینید منطق شما کجا از رویکرد مورد انتظار فاصله می‌گیرد.

مقایسه قالب‌های خروجی Diff

ابزارهای diff خروجی را در چندین قالب تولید می‌کنند. جدول زیر رایج‌ترین آن‌ها، آنچه آن‌ها را تولید می‌کند، و زمان مفید بودن هر کدام را خلاصه می‌کند.

قالبابزار / منبعتوضیح
Unified diffdiff -u / git diffPrefixes lines with + / - / space; includes @@ hunk headers
Side-by-sidediff -y / sdiffTwo columns, changed lines aligned horizontally
Context diffdiff -cShows changed lines with surrounding context, marked with ! / + / -
HTML diffPython difflibColor-coded HTML table with inline change highlights
JSON PatchRFC 6902Array of add/remove/replace operations on a JSON document

نحوه کار مقایسه خطوط: الگوریتم LCS

اکثر ابزارهای مقایسه خط، از جمله این ابزار، از الگوریتم طولانی‌ترین زیردنباله مشترک (LCS) استفاده می‌کنند. LCS بزرگ‌ترین مجموعه خطوطی را پیدا می‌کند که در هر دو متن به همان ترتیب نسبی ظاهر می‌شوند، بدون اینکه نیازی به پیوستگی داشته باشند. خطوطی که در LCS نیستند تفاوت‌های واقعی هستند.

الگوریتم استاندارد LCS از برنامه‌نویسی پویا استفاده می‌کند و در زمان O(m x n) اجرا می‌شود، که m و n تعداد خطوط دو متن هستند. برای فایل‌های بزرگ، انواع بهینه‌شده مانند الگوریتم diff مایرز (Myers' diff algorithm) که توسط Git استفاده می‌شود، این را به O(n + d^2) کاهش می‌دهد که d تعداد تفاوت‌هاست، که باعث می‌شود هنگامی که بیشتر خطوط مشترک هستند سریع باشد.

۱. ساخت جدول DP
یک ماتریس (m+1) x (n+1) ایجاد کنید. برای هر جفت خط، طول طولانی‌ترین زیردنباله مشترک دیده‌شده تا کنون را ذخیره کنید. خطوط برابر مقدار قطری را یک واحد افزایش می‌دهند.
۲. ردیابی معکوس
از گوشه پایین‌راست ماتریس به سمت (0,0) حرکت کنید. حرکت‌های قطری روی خطوط برابر ورودی‌های «بدون تغییر» تولید می‌کنند. حرکت‌های افقی یا عمودی ورودی‌های «افزوده‌شده» یا «حذف‌شده» تولید می‌کنند.
۳. رندر خروجی
هر ورودی را به یک خط نمایشی نگاشت کنید: خطوط بدون تغییر پیشوند ندارند، خطوط افزوده‌شده + می‌گیرند، خطوط حذف‌شده - می‌گیرند. رنگ‌بندی برای وضوح تصویری اعمال کنید.

نمونه‌های کد

پیاده‌سازی مقایسه متن خط‌به‌خط در JavaScript، Python، Go و خط فرمان. هر نمونه خروجی به سبک unified diff تولید می‌کند.

JavaScript
// Line-by-line diff using the LCS algorithm
function diffLines(a, b) {
  const linesA = a.split('\n')
  const linesB = b.split('\n')

  // Build LCS table
  const m = linesA.length, n = linesB.length
  const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0))
  for (let i = 1; i <= m; i++)
    for (let j = 1; j <= n; j++)
      dp[i][j] = linesA[i-1] === linesB[j-1]
        ? dp[i-1][j-1] + 1
        : Math.max(dp[i-1][j], dp[i][j-1])

  // Backtrack to produce diff
  const result = []
  let i = m, j = n
  while (i > 0 || j > 0) {
    if (i > 0 && j > 0 && linesA[i-1] === linesB[j-1]) {
      result.unshift({ type: 'equal', text: linesA[i-1] }); i--; j--
    } else if (j > 0 && (i === 0 || dp[i][j-1] >= dp[i-1][j])) {
      result.unshift({ type: 'add', text: linesB[j-1] }); j--
    } else {
      result.unshift({ type: 'remove', text: linesA[i-1] }); i--
    }
  }
  return result
}

const diff = diffLines("alpha\nbeta\ngamma", "alpha\nbeta changed\ngamma\ndelta")
// → [
//   { type: 'equal',  text: 'alpha' },
//   { type: 'remove', text: 'beta' },
//   { type: 'add',    text: 'beta changed' },
//   { type: 'equal',  text: 'gamma' },
//   { type: 'add',    text: 'delta' }
// ]
Python
import difflib

text_a = """alpha
beta
gamma""".splitlines()

text_b = """alpha
beta changed
gamma
delta""".splitlines()

# Unified diff (same format as git diff)
for line in difflib.unified_diff(text_a, text_b, fromfile='a.txt', tofile='b.txt', lineterm=''):
    print(line)
# --- a.txt
# +++ b.txt
# @@ -1,3 +1,4 @@
#  alpha
# -beta
# +beta changed
#  gamma
# +delta

# HTML side-by-side diff
d = difflib.HtmlDiff()
html = d.make_file(text_a, text_b, fromdesc='Original', todesc='Modified')
Go
package main

import (
	"fmt"
	"strings"
)

// Minimal LCS-based line diff
func diffLines(a, b string) {
	la := strings.Split(a, "\n")
	lb := strings.Split(b, "\n")
	m, n := len(la), len(lb)

	dp := make([][]int, m+1)
	for i := range dp {
		dp[i] = make([]int, n+1)
	}
	for i := 1; i <= m; i++ {
		for j := 1; j <= n; j++ {
			if la[i-1] == lb[j-1] {
				dp[i][j] = dp[i-1][j-1] + 1
			} else if dp[i-1][j] >= dp[i][j-1] {
				dp[i][j] = dp[i-1][j]
			} else {
				dp[i][j] = dp[i][j-1]
			}
		}
	}

	var result []string
	i, j := m, n
	for i > 0 || j > 0 {
		if i > 0 && j > 0 && la[i-1] == lb[j-1] {
			result = append([]string{" " + la[i-1]}, result...)
			i--; j--
		} else if j > 0 && (i == 0 || dp[i][j-1] >= dp[i-1][j]) {
			result = append([]string{"+" + lb[j-1]}, result...)
			j--
		} else {
			result = append([]string{"-" + la[i-1]}, result...)
			i--
		}
	}

	for _, line := range result {
		fmt.Println(line)
	}
}

// Output:
//  alpha
// -beta
// +beta changed
//  gamma
// +delta
CLI (diff / git)
# Compare two files with unified diff (3 lines of context)
diff -u original.txt modified.txt

# Git diff between working tree and last commit
git diff HEAD -- file.txt

# Git diff between two branches
git diff main..feature -- src/

# Side-by-side diff in the terminal
diff -y --width=120 original.txt modified.txt

# Color-coded diff (requires colordiff)
diff -u original.txt modified.txt | colordiff

سوالات متداول

تفاوت بین مقایسه خطوط و مقایسه کاراکترها چیست؟
مقایسه خطوط متن را خط‌به‌خط مقایسه می‌کند: اگر هر کاراکتری در یک خط تغییر کند، کل آن خط به عنوان حذف‌شده و نسخه جدید به عنوان افزوده‌شده علامت‌گذاری می‌شود. مقایسه کاراکتری (یا word diff) با دقت بیشتری کار می‌کند و کاراکترها یا کلمات خاصی را که در یک خط تغییر کرده‌اند علامت‌گذاری می‌کند. مقایسه خطوط برای بازبینی کد استاندارد است؛ مقایسه کاراکتری برای ویرایش متن مفیدتر است.
git diff در داخل چگونه کار می‌کند؟
Git به‌طور پیش‌فرض از الگوریتم diff مایرز (Myers' diff algorithm) استفاده می‌کند که کوتاه‌ترین اسکریپت ویرایشی (حداقل تعداد درج و حذف) بین دو فایل را پیدا می‌کند. Git نتیجه را در قالب unified diff با هدرهای @@ ذخیره می‌کند که شماره خطوط را مشخص می‌کنند. وقتی git diff اجرا می‌کنید، Git درخت کاری را در برابر index (ناحیه staging) مقایسه می‌کند، نه آخرین commit، مگر اینکه HEAD را به‌صراحت ارسال کنید.
آیا می‌توانم فایل‌های باینری را با ابزار مقایسه متن مقایسه کنم؟
خیر. ابزارهای مقایسه متن ورودی را بر اساس کاراکترهای سطر جدید تقسیم و رشته‌ها را مقایسه می‌کنند. فایل‌های باینری حاوی دنباله‌های بایت دلخواه هستند که تقسیم‌بندی خطوط بی‌معنی ایجاد می‌کنند. برای مقایسه باینری، از یک ابزار hex diff یا مقایسه checksum سطح فایل (sha256sum روی هر دو فایل) استفاده کنید.
آیا داده‌های من هنگام استفاده از این ابزار به سرور ارسال می‌شوند؟
خیر. این ابزار کاملاً در مرورگر شما اجرا می‌شود. محاسبه diff از یک پیاده‌سازی LCS در JavaScript استفاده می‌کند که در سمت کلاینت اجرا می‌شود. هیچ درخواست شبکه‌ای با محتوای متن شما ارسال نمی‌شود. می‌توانید این را با باز کردن تب Network مرورگر خود هنگام استفاده از ابزار تأیید کنید.
قالب unified diff چیست؟
unified diff قالب خروجی است که توسط diff -u و git diff استفاده می‌شود. خطوط تغییریافته را با پیشوند - (حذف‌شده) و + (افزوده‌شده) نمایش می‌دهد و پیش از آن‌ها هدرهای @@ قرار می‌گیرند که محدوده شماره خطوط در هر دو فایل را مشخص می‌کنند. خطوط زمینه (بدون تغییر) پیشوند فاصله دارند. unified diff رایج‌ترین قالب برای patch‌ها، pull request‌ها و ابزارهای بازبینی کد است.
چطور فایل‌های بزرگ با تفاوت‌های زیاد را مقایسه کنم؟
برای فایل‌هایی با هزاران خط، ابزار مبتنی بر مرورگر کار می‌کند اما ممکن است کند شود چون الگوریتم LCS به‌صورت درجه دوم مقیاس می‌شود. برای diff‌های بسیار بزرگ، ابزارهای خط فرمان مانند diff یا git diff سریع‌ترند چون از پیاده‌سازی‌های بهینه‌شده C استفاده می‌کنند و می‌توانند خروجی را جریانی ارسال کنند. همچنین می‌توانید خطوط بدون تغییر را فیلتر کنید (گزینه «نمایش خط‌های تغییرنیافته» را در این ابزار خاموش کنید) تا تنها روی تغییرات تمرکز کنید.
three-way merge diff چیست؟
یک three-way merge دو نسخه ویرایش‌شده از یک فایل را در برابر نیای مشترک آن‌ها (پایه) مقایسه می‌کند. Git این را در طول git merge و git rebase استفاده می‌کند. تغییرات انجام‌شده در هر شاخه نسبت به پایه را شناسایی و با هم ترکیب می‌کند. وقتی هر دو شاخه یک خط مشابه را تغییر دهند، Git یک تعارض ادغام گزارش می‌دهد. three-way merge به سه ورودی نیاز دارد، در حالی که یک diff استاندارد تنها به دو ورودی نیاز دارد.