尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

比较两文件差异python实现

发布时间:2026/9/29 2:20:14

资讯中心
01
ARTICLE

比较两文件差异python实现

比较两文件差异python实现
比较1比较2下面的是GUI方式俩栏颜色对比较适合前后有改动的同一文档import sysfrom difflib import SequenceMatcherfrom PySide6.QtCore import Qt, QRegularExpressionfrom PySide6.QtGui import (QFont, QColor, QSyntaxHighlighter, QTextCharFormat,QTextCursor, QTextDocument)from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,QHBoxLayout, QPlainTextEdit, QPushButton, QFileDialog,QLabel, QSplitter)# ---------- Diff 计算 ----------def compute_diff(a_lines, b_lines):返回 b_lines 的标注列表: (equal|add|del|change, line, a_idx)sm SequenceMatcher(None, a_lines, b_lines, autojunkFalse)result []for tag, i1, i2, j1, j2 in sm.get_opcodes():if tag equal:for k in range(j2 - j1):result.append((equal, b_lines[j1 k], i1 k))elif tag insert:for k in range(j1, j2):result.append((add, b_lines[k], None))elif tag delete:for k in range(i1, i2):result.append((del, a_lines[k], k))elif tag replace:for k in range(j1, j2):result.append((change, b_lines[k], None))for k in range(i1, i2):result.append((del, a_lines[k], k))return result# ---------- 高亮器 ----------COLORS {equal: QColor(#F5F5F5),add: QColor(#C8E6C9), # 浅绿del: QColor(#FFCDD2), # 浅红change: QColor(#FFF59D), # 浅黄}class DiffHighlighter(QSyntaxHighlighter):def __init__(self, doc, marks):super().__init__(doc)self.marks marks # list[bool] —— 长度等于行数def highlightBlock(self, text):block_num self.currentBlock().blockNumber()if block_num len(self.marks) and self.marks[block_num]:fmt QTextCharFormat()fmt.setBackground(QColor(#FFEB3B))fmt.setProperty(QTextCharFormat.Property.FullWidthSelection, True)self.setFormat(0, len(text), fmt)# ---------- 主窗口 ----------class DiffWindow(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle(Python Diff Viewer)self.resize(1200, 700)central QWidget(); self.setCentralWidget(central)v QVBoxLayout(central)# 顶部按钮栏bar QHBoxLayout()self.btn_left QPushButton( 打开左文件)self.btn_right QPushButton( 打开右文件)self.btn_diff QPushButton( 对比)for b in (self.btn_left, self.btn_right, self.btn_diff):bar.addWidget(b)bar.addStretch()v.addLayout(bar)# 左右文本框self.left QPlainTextEdit(); self.left.setFont(QFont(Consolas, 11))self.right QPlainTextEdit(); self.right.setFont(QFont(Consolas, 11))for ed in (self.left, self.right):ed.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)splitter QSplitter(Qt.Orientation.Horizontal)splitter.addWidget(self._wrap(左文件 (原版本), self.left))splitter.addWidget(self._wrap(右文件 (新版本), self.right))splitter.setSizes([600, 600])v.addWidget(splitter)# 信号self.btn_left.clicked.connect(lambda: self._open(self.left))self.btn_right.clicked.connect(lambda: self._open(self.right))self.btn_diff.clicked.connect(self._run_diff)def _wrap(self, title, edit):w QWidget(); lay QVBoxLayout(w); lay.setContentsMargins(0,0,0,0)lay.addWidget(QLabel(title))lay.addWidget(edit)return wdef _open(self, editor):path, _ QFileDialog.getOpenFileName(self, 选择文件)if path:with open(path, r, encodingutf-8, errorsignore) as f:editor.setPlainText(f.read())def _run_diff(self):a self.left.toPlainText().splitlines()b self.right.toPlainText().splitlines()diff compute_diff(a, b)# --- 左文件按 a 的顺序仅显示 del/equal ---left_marks []left_lines []# 同步高亮把 b 的 add/change 也映射到 a 侧对应行a_highlight set() # 在 a 中需要高亮的行号与 b 的 add/change 对齐# 重新跑一遍以同步两侧位置sm SequenceMatcher(None, a, b, autojunkFalse)a_pos, b_pos 0, 0a_blocks, b_blocks [], []for tag, i1, i2, j1, j2 in sm.get_opcodes():if tag equal:for k in range(i2 - i1):a_blocks.append((equal, a[i1k], i1k))b_blocks.append((equal, b[j1k], j1k))elif tag insert:for k in range(j1, j2):a_blocks.append((pad, , i1))b_blocks.append((add, b[k], j1k))elif tag delete:for k in range(i1, i2):a_blocks.append((del, a[k], i1k))b_blocks.append((pad, , j1))elif tag replace:# 先用 a 行标 del再用 b 行标 add/changefor k in range(i1, i2):a_blocks.append((del, a[k], i1k))b_blocks.append((pad, , j1k))for k in range(j1, j2):a_blocks.append((pad, , i1k))b_blocks.append((change, b[k], j1k))# 渲染到文本框 上色self._render(self.left, a_blocks)self._render(self.right, b_blocks)def _render(self, editor, blocks):editor.setPlainText(\n.join(b[1] for b in blocks))cursor editor.textCursor()cursor.select(QTextCursor.SelectionType.Document)fmt_default QTextCharFormat(); fmt_default.setBackground(QColor(white))cursor.setCharFormat(fmt_default)cursor.clearSelection()for i, (tag, _, _) in enumerate(blocks):color COLORS.get(tag)if not color: continueblock editor.document().findBlockByNumber(i)hl QTextCursor(block)hl.movePosition(QTextCursor.MoveOperation.EndOfBlock,QTextCursor.MoveMode.KeepAnchor)fmt QTextCharFormat(); fmt.setBackground(color)hl.setCharFormat(fmt)editor.viewport().update()if __name__ __main__:app QApplication(sys.argv)w DiffWindow(); w.show()sys.exit(app.exec())但缺行号显示补充
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。