显示两个文件不一致的内容的实现(细胞分裂的方法)

       对于相关的实现前人已经做得很好了,winmerge就是其中非常成功的软件。笔者重新实现只是因为winmerge的报表功能不能提供我需要的形式的报表。对此,也处于兴趣,按照自己的比较算法实现了一个这样的功能。

    先简述一下算法思路,这个算法虽说是寻找不一致的内容,但算法的实习是以尽可能找到对应的一致内容为基础。剥除一致的内容,剩下的就是不一致的内容。算法存在这样的一个假设,比较的两个文件目标文件只有少量是不一样的,大部分都是一致的。更进一步说,文件B是在文件A的基础上进行的修改。其修内容可能是在某个位置加了一行,删除了一行,或者修改了某一行等等。这个假设并不过分,因为如果比较两个面目全非的文件,比较的结果并没有参考价值。现在用个简单的例子描述下比较过程。

字符串1:AABBCCDDEEFF

字符串2:AABBBDCDDEEFFG

 

步骤1:

为了得字符串1和字符串1不一致之处,第一步先匹配出最大一致的字符串。这里一致的字符串有

AABB ,CDDEEFF,暂且称为"可能对应组",这里有两个对应组。(这里的一致,表示从字符串1的某个位置开始的一段距离和字符串2完全一致。它们存在可能对应的关系,如果真的存在对应,称为"真实对应组",它表明这个组的字符串是原本没有被修改过的地方)通常"可能对应组"不仅有一个,我们认定字符串长度最长的"可能对应组",是"真实对应组",这里是CDDEEFF。将"真实对应组"分别从两个字符串取出。 我们得到一下的一组比较值。

 

字符串1:AABBC     (CDDEEFF)      null

字符串2:AABBBD   (CDDEEFF)      G  

括号代表"真实对应组",已经去除的部分,null代表空字符串。去除后两个字符串,分裂成了四个字符串。四个字符串亮亮之间存在空间的对应关系。也就是修改前和修改后的关系。我们把字符串1.1和字符串2.1称之为"对应块"1,我们把字符串1.2和字符串2.2称为"对应块"2.

字符串1.1:AABBC         字符串1.2:null

字符串2.1:AABBBD       字符串2.2: G  

 

步骤2:按照步骤1的方法比较每个"对应块"。分裂成四个"对应块"

......重复以上步骤。

 

最终结果是已经不存在"真实对应组"。现在每个"对应块"就是文件不一致的部分。这里为了说明用字符串来比较,如果是比较文件应该会用行来比较。A可能代表的是若干行.

给出.net代码的实现
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace CompareFile
{
    public class CompareFile
    {
        public string output = string.Empty;
        public string dir1 = string.Empty;
        public string dir2 = string.Empty;
        public OutPutBase OutTool = null;

        //入口函数
        public void DoCompareFile()
        {
            DoCompareFile(null);
        }
        //比较的文件列表
        public void DoCompareFile(string[] files)
        {
            if (files == null || files.Length == 0)
            {
                if (output != string.Empty && dir1 != string.Empty && dir2 != string.Empty)
                    CheckDir(new DirectoryInfo(dir1));
            }
            else
            {
                CheckFiles(files);
            }
        }

        //比较目标文件夹
        private void CheckDir(DirectoryInfo dir)
        {
            if (OutTool == null)
                OutTool = new OutPutBase();

            OutTool.outFile = output;
            foreach (FileInfo file in dir.GetFiles())
            {
                if (file.Extension == ".cs" || file.Extension == ".aspx.cs" || file.Extension == ".aspx")
                {
                    System.Console.WriteLine(file.Name);
                    string Tem = dir.FullName.Replace(dir1, dir2);
                    string File2 = Tem + "//" + file.Name;
                    CompareList(file.FullName, GetFileList(file.FullName), GetFileList(File2));
                }
            }
            foreach (DirectoryInfo d in dir.GetDirectories())
            {
                CheckDir(d);
            }

        }

        //比较文件列表
        private void CheckFiles(string[] files)
        {
            if (OutTool == null)
                OutTool = new OutPutBase();

            OutTool.outFile = output;
            foreach (string fileName in files)
            {
                FileInfo file = new FileInfo(fileName);
                //这里过滤了一下文件类型,实际的应用可以根据需要定义类型
                if (file.Extension == ".cs" || file.Extension == ".aspx.cs" || file.Extension == ".aspx")
                {
                    System.Console.WriteLine(file.Name);
                    string File2 = file.FullName.Replace(dir1, dir2);
                    if (File.Exists(File2))
                    {
                        CompareList(file.FullName, GetFileList(file.FullName), GetFileList(File2));
                    }
                }
            }

        }

        //读取文件形成字符串行集合
        List<string> GetFileList(string FileName)
        {
            List<string> FileList = new List<string>();
            using (StreamReader sw = new StreamReader(FileName, System.Text.Encoding.Default))
            {
                string str = null;
                while ((str = sw.ReadLine()) != null)
                {
                    FileList.Add(str);
                }
            }
            return FileList;
        }
        //比较文件行集合
        void CompareList(string FileName, List<string> FileList1, List<string> FileList2)
        {
            List<string> SameList = new List<string>();

            CompareResult cr = FindMostLen(FileList1, FileList2);
            //结果输出,这里用输出CSV的方式,此处可由读者自行实现
            //最大长度为0代表已经不存在真实对应组
            if (cr.mostLen == 0) OutTool.WriteList(FileName, cr.file2.downFile, cr.file1.downFile);
            else
            {
                CompareList(FileName, cr.file1.upFile, cr.file2.upFile);
                CompareList(FileName, cr.file1.downFile, cr.file2.downFile);
            }

        }
        //自定义类存放比较结果
        class CompareResult
        {
            public int mostLen = 0;
            public result file1 = new result();
            public result file2 = new result();
        }

        //自定义类存放文件块
        class result
        {
            public int mostStart = 0;
            public int mostEnd = 0;
            public List<string> upFile = new List<string>();
            public List<string> downFile = new List<string>();

            public void SetFile(List<string> file)
            {

                upFile = file.GetRange(0, mostStart);
                downFile = file.GetRange(mostEnd, file.Count - mostEnd);
            }
        }

        //寻找真实对应块的过程
        CompareResult FindMostLen(List<string> FileList1, List<string> FileList2)
        {
            CompareResult compareResult = new CompareResult();
            for (int i = 0; i < FileList1.Count; i++)
            {
                int len = 0;
                int start = FileList2.IndexOf(FileList1[i]);
                if (start == -1)
                {
                    continue;
                }
                else
                {
                    int flag = i;
                    int j = start;
                    for (; j < FileList2.Count; j++)
                    {
                        if (flag < FileList1.Count)
                        {
                            if (FileList2[j] == FileList1[flag])
                            {
                                len++;
                                flag++;
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    if (i + len != flag) throw new Exception("err");

                    if (len > compareResult.mostLen)
                    {
                        compareResult.mostLen = len;
                        compareResult.file1.mostStart = i;
                        compareResult.file1.mostEnd = flag;
                        compareResult.file2.mostStart = start;
                        compareResult.file2.mostEnd = j;
                    }

                    i = flag;

                }
            }

            compareResult.file1.SetFile(FileList1);
            compareResult.file2.SetFile(FileList2);

            return compareResult;
        }
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值