UNPKG

text-compare-vue3

Version:

A powerful text comparison plugin for Vue.js with character-level diff support

143 lines (130 loc) 3.54 kB
/** * 计算文本差异 * @param {string} oldText - 原始文本 * @param {string} newText - 新文本 * @param {boolean} isDifferent - 是否存在差异 * @returns {Object} 包含 oldParts 和 newParts 的对象 */ export function getDiffParts(oldText, newText, isDifferent = true) { if (!isDifferent || !oldText || !newText) { return { oldParts: [{ value: oldText || '-', removed: false }], newParts: [{ value: newText || '-', added: false }] } } const oldParts = [] const newParts = [] // 将文本转换为字符数组 const oldChars = Array.from(oldText) const newChars = Array.from(newText) // 构建相似度矩阵 const matrix = [] for (let i = 0; i <= oldChars.length; i++) { matrix[i] = [] for (let j = 0; j <= newChars.length; j++) { if (i === 0 || j === 0) { matrix[i][j] = 0 } else if (oldChars[i - 1] === newChars[j - 1]) { matrix[i][j] = matrix[i - 1][j - 1] + 1 } else { matrix[i][j] = Math.max(matrix[i - 1][j], matrix[i][j - 1]) } } } // 回溯找出相同的部分 let i = oldChars.length let j = newChars.length const commonParts = [] while (i > 0 && j > 0) { if (oldChars[i - 1] === newChars[j - 1]) { commonParts.unshift({ char: oldChars[i - 1], oldIndex: i - 1, newIndex: j - 1 }) i-- j-- } else if (matrix[i - 1][j] > matrix[i][j - 1]) { i-- } else { j-- } } // 根据commonParts构建差异结果 let lastOldIndex = -1 let lastNewIndex = -1 // 处理开头的差异 if (commonParts.length > 0) { if (commonParts[0].oldIndex > 0) { oldParts.push({ value: oldText.slice(0, commonParts[0].oldIndex), removed: true }) } if (commonParts[0].newIndex > 0) { newParts.push({ value: newText.slice(0, commonParts[0].newIndex), added: true }) } } // 处理中间的差异 for (let k = 0; k < commonParts.length; k++) { const current = commonParts[k] const next = commonParts[k + 1] // 添加相同的字符 oldParts.push({ value: current.char, removed: false }) newParts.push({ value: current.char, added: false }) if (next) { // 处理旧文本中的差异 if (next.oldIndex - current.oldIndex > 1) { oldParts.push({ value: oldText.slice(current.oldIndex + 1, next.oldIndex), removed: true }) } // 处理新文本中的差异 if (next.newIndex - current.newIndex > 1) { newParts.push({ value: newText.slice(current.newIndex + 1, next.newIndex), added: true }) } } lastOldIndex = current.oldIndex lastNewIndex = current.newIndex } // 处理结尾的差异 if (commonParts.length > 0) { const lastCommon = commonParts[commonParts.length - 1] if (lastCommon.oldIndex < oldChars.length - 1) { oldParts.push({ value: oldText.slice(lastCommon.oldIndex + 1), removed: true }) } if (lastCommon.newIndex < newChars.length - 1) { newParts.push({ value: newText.slice(lastCommon.newIndex + 1), added: true }) } } else { // 如果没有相同部分,则全部标记为差异 oldParts.push({ value: oldText, removed: true }) newParts.push({ value: newText, added: true }) } return { oldParts, newParts } }