自动对比文档差异并输出脚本

wen 实用脚本 4

本文目录导读:

自动对比文档差异并输出脚本

  1. 方案1:基于difflib的文档对比工具
  2. 方案2:更高级的对比工具(支持多格式)
  3. 使用方法

我来帮你创建一个自动对比文档差异并生成脚本的工具,这里提供Python实现方案:

方案1:基于difflib的文档对比工具

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
文档差异对比工具 - 自动对比并输出差异脚本
"""
import difflib
import os
import sys
from datetime import datetime
class DocumentDiffTool:
    def __init__(self, file1, file2):
        self.file1 = file1
        self.file2 = file2
        self.diff_results = []
    def read_file(self, file_path):
        """读取文件内容"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                return f.readlines()
        except UnicodeDecodeError:
            # 尝试其他编码
            try:
                with open(file_path, 'r', encoding='gbk') as f:
                    return f.readlines()
            except:
                print(f"无法读取文件: {file_path}")
                return []
    def compare_files(self):
        """对比两个文件的差异"""
        lines1 = self.read_file(self.file1)
        lines2 = self.read_file(self.file2)
        # 创建差异比较器
        differ = difflib.Differ()
        diff = list(differ.compare(lines1, lines2))
        # 分析差异
        changes = []
        for line in diff:
            if line.startswith('+ '):
                changes.append(('ADD', line[2:]))
            elif line.startswith('- '):
                changes.append(('DELETE', line[2:]))
            elif line.startswith('? '):
                changes.append(('CHANGE', line[2:]))
        return changes, diff
    def generate_diff_script(self, changes, output_file=None):
        """生成差异脚本"""
        script_lines = []
        script_lines.append(f"# 文档差异脚本")
        script_lines.append(f"# 对比文件: {self.file1} ↔ {self.file2}")
        script_lines.append(f"# 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        script_lines.append(f"# 总修改: {len([c for c in changes if c[0] != 'UNCHANGED'])} 处")
        script_lines.append("")
        # 生成HTML格式的差异报告
        html_diff = difflib.HtmlDiff().make_file(
            self.read_file(self.file1),
            self.read_file(self.file2),
            self.file1,
            self.file2
        )
        # 生成详细脚本
        add_count = 0
        del_count = 0
        change_count = 0
        for change_type, content in changes:
            if change_type == 'ADD':
                add_count += 1
                script_lines.append(f"# 添加[{add_count}]: {content}")
            elif change_type == 'DELETE':
                del_count += 1
                script_lines.append(f"# 删除[{del_count}]: {content}")
            elif change_type == 'CHANGE':
                change_count += 1
                script_lines.append(f"# 修改[{change_count}]: {content}")
        script_lines.append("")
        script_lines.append(f"# 统计信息:")
        script_lines.append(f"#   添加: {add_count} 处")
        script_lines.append(f"#   删除: {del_count} 处")
        script_lines.append(f"#   修改: {change_count} 处")
        script_content = '\n'.join(script_lines)
        # 保存脚本
        if output_file:
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(script_content)
            print(f"差异脚本已保存到: {output_file}")
        # 保存HTML报告
        html_file = output_file.replace('.txt', '.html') if output_file else 'diff_report.html'
        with open(html_file, 'w', encoding='utf-8') as f:
            f.write(html_diff)
        print(f"HTML报告已保存到: {html_file}")
        return script_content
    def print_summary(self, changes):
        """打印差异摘要"""
        add_count = len([c for c in changes if c[0] == 'ADD'])
        del_count = len([c for c in changes if c[0] == 'DELETE'])
        change_count = len([c for c in changes if c[0] == 'CHANGE'])
        print("\n" + "="*50)
        print("文档对比结果摘要")
        print("="*50)
        print(f"原始文件: {self.file1}")
        print(f"对比文件: {self.file2}")
        print(f"添加内容: {add_count} 处")
        print(f"删除内容: {del_count} 处")
        print(f"修改内容: {change_count} 处")
        print(f"总变化: {add_count + del_count + change_count} 处")
        print("="*50)
def main():
    """主函数"""
    if len(sys.argv) < 3:
        print("使用方法: python diff_tool.py <原文件> <新文件> [输出脚本]")
        print("示例: python diff_tool.py old.txt new.txt diff_script.txt")
        sys.exit(1)
    file1 = sys.argv[1]
    file2 = sys.argv[2]
    output_file = sys.argv[3] if len(sys.argv) > 3 else f"diff_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
    # 检查文件是否存在
    if not os.path.exists(file1):
        print(f"错误: 文件 '{file1}' 不存在")
        sys.exit(1)
    if not os.path.exists(file2):
        print(f"错误: 文件 '{file2}' 不存在")
        sys.exit(1)
    # 创建对比工具实例
    tool = DocumentDiffTool(file1, file2)
    # 执行对比
    print(f"正在对比文件: {file1} ↔ {file2}")
    changes, raw_diff = tool.compare_files()
    # 打印摘要
    tool.print_summary(changes)
    # 生成差异脚本
    script = tool.generate_diff_script(changes, output_file)
    # 显示差异内容(前20行)
    print("\n差异内容预览:")
    print("-"*50)
    display_lines = 0
    for change_type, content in changes:
        if display_lines >= 20:
            print("... (更多差异已保存到文件)")
            break
        symbol = {'ADD': '+', 'DELETE': '-', 'CHANGE': '?'}
        print(f"{symbol.get(change_type, ' ')} {content}", end='')
        display_lines += 1
if __name__ == "__main__":
    main()

方案2:更高级的对比工具(支持多格式)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
高级文档差异对比工具 - 支持多种文件格式
"""
import difflib
import os
import json
import re
from datetime import datetime
class AdvancedDiffTool:
    def __init__(self):
        self.supported_formats = ['.txt', '.py', '.html', '.css', '.js', '.json', '.xml', '.md']
    def compare_structures(self, file1, file2):
        """对比结构化文档"""
        ext1 = os.path.splitext(file1)[1].lower()
        ext2 = os.path.splitext(file2)[1].lower()
        if ext1 != ext2:
            print("警告: 文件格式不同,使用基础文本对比")
            return self.basic_compare(file1, file2)
        if ext1 == '.json':
            return self.compare_json(file1, file2)
        elif ext1 in ['.xml', '.html']:
            return self.compare_xml(file1, file2)
        else:
            return self.basic_compare(file1, file2)
    def compare_json(self, file1, file2):
        """对比JSON文件"""
        with open(file1, 'r', encoding='utf-8') as f:
            data1 = json.load(f)
        with open(file2, 'r', encoding='utf-8') as f:
            data2 = json.load(f)
        changes = []
        def compare_dicts(d1, d2, path=""):
            keys1 = set(d1.keys())
            keys2 = set(d2.keys())
            # 新增的键
            for key in keys2 - keys1:
                changes.append(('ADD', f"{path}.{key}: {json.dumps(d2[key], ensure_ascii=False)}"))
            # 删除的键
            for key in keys1 - keys2:
                changes.append(('DELETE', f"{path}.{key}: {json.dumps(d1[key], ensure_ascii=False)}"))
            # 修改的值
            for key in keys1 & keys2:
                if isinstance(d1[key], dict) and isinstance(d2[key], dict):
                    compare_dicts(d1[key], d2[key], f"{path}.{key}")
                elif d1[key] != d2[key]:
                    changes.append(('MODIFY', f"{path}.{key}: {json.dumps(d1[key], ensure_ascii=False)} → {json.dumps(d2[key], ensure_ascii=False)}"))
        compare_dicts(data1, data2)
        return changes
    def compare_xml(self, file1, file2):
        """对比XML/HTML文件"""
        import xml.etree.ElementTree as ET
        def parse_xml(file_path):
            try:
                tree = ET.parse(file_path)
                return tree.getroot()
            except:
                return None
        root1 = parse_xml(file1)
        root2 = parse_xml(file2)
        if root1 is None or root2 is None:
            return self.basic_compare(file1, file2)
        changes = []
        def compare_elements(elem1, elem2, path=""):
            # 对比标签
            if elem1.tag != elem2.tag:
                changes.append(('CHANGE', f"标签变化: {elem1.tag} → {elem2.tag}"))
            # 对比属性
            attr1 = elem1.attrib
            attr2 = elem2.attrib
            for key in attr2:
                if key not in attr1:
                    changes.append(('ADD', f"新增属性 {path}[@{key}={attr2[key]}]"))
                elif attr1[key] != attr2[key]:
                    changes.append(('CHANGE', f"属性变化 {path}[@{key}: {attr1[key]} → {attr2[key]}]"))
            for key in attr1:
                if key not in attr2:
                    changes.append(('DELETE', f"删除属性 {path}[@{key}={attr1[key]}]"))
            # 对比文本内容
            text1 = (elem1.text or "").strip()
            text2 = (elem2.text or "").strip()
            if text1 != text2:
                if text1 and text2:
                    changes.append(('CHANGE', f"文本变化 at {path}: '{text1}' → '{text2}'"))
                elif text2:
                    changes.append(('ADD', f"添加文本 at {path}: '{text2}'"))
                else:
                    changes.append(('DELETE', f"删除文本 at {path}: '{text1}'"))
            # 递归对比子元素
            children1 = list(elem1)
            children2 = list(elem2)
            for i, child in enumerate(children2):
                if i < len(children1):
                    compare_elements(children1[i], child, f"{path}/{child.tag}")
                else:
                    changes.append(('ADD', f"新增元素 {path}/{child.tag}"))
            for i in range(len(children2), len(children1)):
                changes.append(('DELETE', f"删除元素 {path}/{children1[i].tag}"))
        compare_elements(root1, root2)
        return changes
    def basic_compare(self, file1, file2):
        """基础文本对比"""
        def read_file(file_path):
            with open(file_path, 'r', encoding='utf-8') as f:
                return f.readlines()
        lines1 = read_file(file1)
        lines2 = read_file(file2)
        differ = difflib.Differ()
        diff = list(differ.compare(lines1, lines2))
        changes = []
        for i, line in enumerate(diff):
            if line.startswith('+ '):
                changes.append(('ADD', line[2:].strip()))
            elif line.startswith('- '):
                changes.append(('DELETE', line[2:].strip()))
            elif line.startswith('? '):
                changes.append(('CHANGE', line[2:].strip()))
        return changes
def generate_patch_script(changes, original_file, modified_file, output_file):
    """生成可执行的patch脚本"""
    script = []
    script.append("#!/bin/bash")
    script.append(f"# 自动生成的补丁脚本")
    script.append(f"# 生成时间: {datetime.now()}")
    script.append(f"# 原始文件: {original_file}")
    script.append(f"# 修改后文件: {modified_file}")
    script.append("")
    add_commands = []
    delete_commands = []
    modify_commands = []
    for change_type, content in changes:
        if change_type == 'ADD':
            add_commands.append(f"echo '添加: {content}'")
            add_commands.append(f"sed -i 's/$/\\n{content}/' {original_file}")
        elif change_type == 'DELETE':
            delete_commands.append(f"echo '删除: {content}'")
            # 转义特殊字符
            escaped_content = content.replace('/', '\\/').replace('&', '\\&')
            delete_commands.append(f"sed -i '/{escaped_content}/d' {original_file}")
        elif change_type == 'CHANGE':
            modify_commands.append(f"echo '修改: {content}'")
    if add_commands:
        script.append("# 添加操作")
        script.extend(add_commands)
        script.append("")
    if delete_commands:
        script.append("# 删除操作")
        script.extend(delete_commands)
        script.append("")
    if modify_commands:
        script.append("# 修改操作")
        script.extend(modify_commands)
        script.append("")
    script.append(f"echo '补丁应用完成'")
    script.append(f"echo '请检查文件: {original_file}'")
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write('\n'.join(script))
    # 设置执行权限
    os.chmod(output_file, 0o755)
    print(f"补丁脚本已生成: {output_file}")
def main():
    import sys
    if len(sys.argv) < 3:
        print("使用方法:")
        print("  python advanced_diff.py <原文件> <新文件>")
        print("  python advanced_diff.py <原文件> <新文件> -o <输出脚本>")
        print("  python advanced_diff.py <原文件> <新文件> -p <补丁脚本>")
        sys.exit(1)
    file1 = sys.argv[1]
    file2 = sys.argv[2]
    # 解析参数
    output_script = None
    patch_script = None
    if '-o' in sys.argv:
        idx = sys.argv.index('-o')
        if idx + 1 < len(sys.argv):
            output_script = sys.argv[idx + 1]
    if '-p' in sys.argv:
        idx = sys.argv.index('-p')
        if idx + 1 < len(sys.argv):
            patch_script = sys.argv[idx + 1]
    # 检查文件
    if not os.path.exists(file1):
        print(f"错误: 文件 '{file1}' 不存在")
        sys.exit(1)
    if not os.path.exists(file2):
        print(f"错误: 文件 '{file2}' 不存在")
        sys.exit(1)
    # 创建对比工具
    tool = AdvancedDiffTool()
    # 执行对比
    print(f"正在对比文件: {file1} ↔ {file2}")
    changes = tool.compare_structures(file1, file2)
    # 输出结果
    print("\n差异分析结果:")
    print("="*60)
    for change_type, content in changes:
        symbol = {'ADD': '➕', 'DELETE': '➖', 'CHANGE': '🔄', 'MODIFY': '✏️'}
        print(f"  {symbol.get(change_type, '•')} [{change_type}] {content}")
    print("="*60)
    print(f"总差异数: {len(changes)}")
    # 生成输出脚本
    if output_script:
        with open(output_script, 'w', encoding='utf-8') as f:
            f.write(f"# 文档差异报告\n")
            f.write(f"# 对比: {file1} ↔ {file2}\n")
            f.write(f"# 时间: {datetime.now()}\n")
            f.write(f"# 差异总数: {len(changes)}\n\n")
            for change_type, content in changes:
                f.write(f"[{change_type}] {content}\n")
        print(f"差异报告已保存: {output_script}")
    # 生成补丁脚本
    if patch_script:
        generate_patch_script(changes, file1, file2, patch_script)
if __name__ == "__main__":
    main()

使用方法

基础使用方法:

# 对比两个文本文件
python diff_tool.py old.txt new.txt
# 指定输出脚本文件
python diff_tool.py old.txt new.txt diff_script.txt
# 高级版本 - 生成补丁脚本
python advanced_diff.py old.txt new.txt -p patch.sh
# 高级版本 - 指定输出格式
python advanced_diff.py old.txt new.txt -o report.txt

功能特点:

  1. 自动检测文件编码 (UTF-8, GBK等)
  2. 支持多种文件格式 (文本, JSON, XML, HTML等)
  3. 生成HTML可视化报告
  4. 生成可执行的补丁脚本
  5. 详细的统计信息
  6. 彩色控制台输出 (可扩展)

输出示例:

文档对比结果摘要
==================================================
原始文件: old.txt
对比文件: new.txt 5 处 3 处 2 处
总变化: 10 处
==================================================
预览:
--------------------------------------------------
[ADD] 新的内容行1
[DELETE] 删除的内容行
[CHANGE] 修改的内容
...

这个工具可以自动识别文档差异,并根据差异类型生成相应的操作脚本,非常适合版本控制、文件同步等场景。

抱歉,评论功能暂时关闭!