টেক্সট ডিফ
দুটি টেক্সট পাশাপাশি তুলনা করুন এবং লাইন-বাই-লাইন পার্থক্য হাইলাইট করুন
টেক্সট A
টেক্সট B
টেক্সট Diff কী?
টেক্সট diff ("difference" শব্দের সংক্ষিপ্ত রূপ) হলো দুটি টেক্সট ব্লক তুলনা করে কোন লাইনগুলি যোগ করা হয়েছে, কোনটি সরানো হয়েছে এবং কোনটি অপরিবর্তিত রয়েছে তা চিহ্নিত করার ফলাফল। এই ধারণাটির উৎপত্তি Unix diff ইউটিলিটি থেকে, যা ১৯৭৪ সালে Version 5 Unix-এর অংশ হিসেবে প্রথম প্রকাশিত হয়। আজ, টেক্সট diff হলো Git-এর মতো ভার্সন কন্ট্রোল সিস্টেমের মূল ভিত্তি, যেখানে প্রতিটি কমিট প্রতিটি ফাইলের পূর্ণ কপির পরিবর্তে একটি diff সংরক্ষণ করে।
একটি diff অ্যালগরিদম দুটি লাইনের ক্রমের মধ্যে Longest Common Subsequence (LCS) খুঁজে বের করে। LCS-এ থাকা লাইনগুলি অপরিবর্তিত হিসেবে চিহ্নিত হয়। মূল টেক্সটে আছে কিন্তু LCS-এ নেই এমন লাইনগুলি সরানো হিসেবে চিহ্নিত হয়। পরিবর্তিত টেক্সটে আছে কিন্তু LCS-এ নেই এমন লাইনগুলি যোগ করা হিসেবে চিহ্নিত হয়। ফলাফল হলো একটি টেক্সটকে অন্যটিতে রূপান্তর করতে প্রয়োজনীয় ন্যূনতম পরিবর্তনের সেট।
Diff আউটপুট বিভিন্ন ফরম্যাটে আসে। Unified diff (git diff-এর ডিফল্ট) সরানো লাইনের আগে মাইনাস চিহ্ন এবং যোগ করা লাইনের আগে প্লাস চিহ্ন যোগ করে। Side-by-side diff উভয় টেক্সটকে সমান্তরাল কলামে সাজায়। এই টুলটি রঙ-কোডেড আউটপুট সহ লাইন-বাই-লাইন তুলনা ব্যবহার করে: যোগ করা লাইনের জন্য সবুজ, সরানো লাইনের জন্য লাল এবং অপরিবর্তিত লাইনের জন্য নিরপেক্ষ রঙ। অপরিবর্তিত লাইনগুলি ডিফল্টভাবে কোনো উপসর্গ ছাড়াই দেখানো হয়, তবে শুধুমাত্র পরিবর্তনের দিকে মনোযোগ দিতে এগুলি লুকানো যেতে পারে।
কেন অনলাইন টেক্সট Diff টুল ব্যবহার করবেন?
টার্মিনালে টেক্সট তুলনা করতে diff ইউটিলিটি ইনস্টল করতে হয় এবং কমান্ড-লাইন ফ্ল্যাগ নিয়ে কাজ করতে হয়। ব্রাউজার-ভিত্তিক diff টুল সেই ঝামেলা সম্পূর্ণ দূর করে।
টেক্সট Diff-এর ব্যবহারের ক্ষেত্র
Diff আউটপুট ফরম্যাটের তুলনা
Diff টুলগুলি বিভিন্ন ফরম্যাটে আউটপুট তৈরি করে। নিচের সারণীতে সবচেয়ে সাধারণ ফরম্যাটগুলি, কী সেগুলি তৈরি করে এবং প্রতিটি কখন উপযোগী তা সংক্ষেপে দেওয়া হলো।
| ফরম্যাট | টুল / উৎস | বিবরণ |
|---|---|---|
| Unified diff | diff -u / git diff | Prefixes lines with + / - / space; includes @@ hunk headers |
| Side-by-side | diff -y / sdiff | Two columns, changed lines aligned horizontally |
| Context diff | diff -c | Shows changed lines with surrounding context, marked with ! / + / - |
| HTML diff | Python difflib | Color-coded HTML table with inline change highlights |
| JSON Patch | RFC 6902 | Array of add/remove/replace operations on a JSON document |
লাইন Diff কীভাবে কাজ করে: LCS অ্যালগরিদম
বেশিরভাগ লাইন-diff টুল, এই টুল সহ, Longest Common Subsequence (LCS) অ্যালগরিদম ব্যবহার করে। LCS উভয় টেক্সটে একই আপেক্ষিক ক্রমে বিদ্যমান লাইনের সবচেয়ে বড় সেট খুঁজে বের করে, সেগুলি একটানা হওয়ার প্রয়োজন ছাড়াই। LCS-এ নেই এমন লাইনগুলিই প্রকৃত পার্থক্য।
মানক LCS অ্যালগরিদম ডায়নামিক প্রোগ্রামিং ব্যবহার করে এবং O(m x n) সময়ে চলে, যেখানে m ও n হলো দুটি টেক্সটের লাইন সংখ্যা। বড় ফাইলের জন্য, Myers' diff অ্যালগরিদমের মতো অপ্টিমাইজড ভেরিয়েন্ট (Git দ্বারা ব্যবহৃত) এটিকে O(n + d^2)-এ কমিয়ে আনে, যেখানে d হলো পার্থক্যের সংখ্যা, যা বেশিরভাগ লাইন একই হলে দ্রুত কাজ করে।
কোড উদাহরণ
JavaScript, Python, Go এবং কমান্ড লাইনে লাইন-বাই-লাইন টেক্সট তুলনার বাস্তবায়ন। প্রতিটি উদাহরণ unified-style diff আউটপুট তৈরি করে।
// 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' }
// ]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')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# 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