Vladimir I. Levenshtein

一、文本对比的列文斯坦距离(编辑距离)算法

在日常应用中,文本比较是一个比较常见的问题。文本比较算法也是一个老生常谈的话题。
文本比较的核心就是比较两个给定的文本(可以是字节流等)之间的差异。目前,主流的比较文本之间的差异主要有两大类。一类是基于编辑距离(Edit Distance)的,例如LD算法。一类是基于最长公共子串的(Longest Common Subsequence),例如Needleman/Wunsch算法等。

列文斯基距离(LD,Levenshtein Distance)又成为编辑距离算法(Edit Distance)。他是以字符串A通过插入字符、删除字符、替换字符变成另一个字符串B,那么操作的过程的次数表示两个字符串的差异。

文件1里面是需要比较的内容,文件2是被比较的文本,现在需要找到在文件1中每一行的文本在文件2中是否存在并相等,如果相等,就在一份结果文件中输出,文件1的哪一行与文件2的哪一行相同,反之不相同就输出文件1的哪一行不相同货不存在。

可以对两段文本进行对比,检测/比较两个文本有什么不同的差异,以便修改,常用于程序代码,就是不需要人工查看,尤其是大文件,有几百上千行的代码,这时候就建议使用比较工具了,不用浪费过多时间去寻找。

为了判断文本文件的内容是否发生变化,确定变化的内容,并尽量降低系统开销,提出了一种基于位置的文本文件比较算法。算法利用位置优先原则,简化了比较过程。实验结果表明该算法可以应用于文件监控,而且易于理解。

二、相似度计算

在自然语言处理任务中,我们经常需要判断两篇文档是否相似、计算两篇文档的相似程度。比如,基于聚类算法发现微博热点话题时,我们需要度量各篇文本的内容相似度,然后让内容足够相似的微博聚成一个簇;在问答系统中,我们会准备一些经典问题和对应的答案,当用户的问题和经典问题很相似时,系统直接返回准备好的答案;在监控新闻稿件在互联网中的传播情况时,我们可以把所有和原创稿件相似的文章,都看作转发,进而刻画原创稿件的传播范围;在对语料进行预处理时,我们需要基于文本的相似度,把重复的文本给挑出来并删掉……总之,文本相似度是一种非常有用的工具,可以帮助我们解决很多问题。

三、尼德曼-翁施算法(Needleman-Wunsch Algorithm)

尼德曼-翁施算法(Needleman-Wunsch Algorithm)是基于生物信息学的知识来匹配蛋白序列或者DNA序列的算法。这是将动态算法应用于生物序列的比较的最早期的几个实例之一。该算法是由 Saul B. Needlman和 Christian D. Wunsch 两位科学家于1970年发明的。本算法高效地解决了如何将一个庞大的数学问题分解为一系列小问题,并且从一系列小问题的解决方法重建大问题的解决方法的过程。该算法也被称为优化匹配算法和整体序列比较法。Needleman-Wunsch 算法仍然被广泛应用于优化整体序列比较中。

蛋白序列?DNA序列?没错,此算法同样用于文本对比。

Saul B. Needlman

Christian D. Wunsch

四、 史密斯-沃特曼算法(Smith-Waterman algorithm)

史密斯-沃特曼算法(Smith-Waterman algorithm)是一种进行局部序列比对(相对于全局比对)的算法,用于找出两个核苷酸序列或蛋白质序列之间的相似区域。该算法的目的不是进行全序列的比对,而是找出两个序列中具有高相似度的片段。
该算法由坦普尔·史密斯(Temple F. Smith)和迈克尔·沃特曼(Michael S. Waterman)于1981年提出。史密斯-沃特曼算法是尼德曼-翁施算法的一个变体,二者都是动态规划算法。这一算法的优势在于可以在给定的打分方法下找出两个序列的最优的局部比对(打分方法使用了置换矩阵和空位罚分)。该算法和尼德曼-翁施算法的主要区别在于该算法不存在负分(负分被替换为零),因此局部比对成为可能。回溯从分数最高的矩阵元素开始,直到遇到分数为零的元素停止。分数最高的局部比对结果在此过程中产生。在实际运用中,人们通常使用该算法的优化版本。

蛋白序列?核苷酸序列?没错,此算法也同样用于文本对比。

Temple F. Smith

Michael S. Waterman

五、 BWT(Burrows-Wheeler Transform 算法)

Burrows-Wheeler 算法,被广泛应用于数据压缩技术中,也可称作块排序压缩,简称 BWT. 1994 年,在加利福尼亚州帕洛阿尔托的 DEC 系统研究中心,Michael Burrows 和 David Wheeler 发明了该算法,故称之为Burrows-Wheeler算法。

压缩算法?没错,可用于文本比较!!!!

Michael Burrows

David Wheeler

六、BLAST生物信息学算法

BLAST是一个被广泛使用于分析生物资讯的程式,因为它可以兼顾我们在做搜寻时的速度以及搜寻结果的精确度。因为当我们所要搜寻的目标数据库非常庞大的时候,速度就变成一项很需要考量的因素。在像BLAST和FASTA这些快速算法被开发之前,我们是使用动态规划算法来作数据库的序列搜寻,这真的非常的耗时。BLAST使用启发式搜索来找出相关的序列,在速度上比完全只使用动态规划大约快上50倍左右,不过它不像动态规划能够保证搜寻到的序列(Database sequence)和所要找的序列(Query sequence)之间的相关性,BLAST的工作就是尽可能找出数据库中和所要查询的序列相关的资讯而已,精确度稍微低一点。此外,BLAST比FASTA更快速,因为BLAST只对比较少出现或是较重要的一些关键字作更进一步的分析,而FASTA是考虑所有共同出现在所要搜寻的序列和目标序列的字。从下面介绍的算法可以更进一步的了解。

BLAST可以让研究者在其中寻找与其感兴趣的序列相同或类似的序列。 例如如果某种非人动物的一个以前未知的基因被发现,研究者一般会在人类基因组中做一个BLAST搜索来确认人类是否包含类似的基因(通过序列的相似性)。BLAST算法以及实现它的程序由美国国家生物技术信息中心(NCBI)的Eugene Myers、Stephen Altschul、Warren Gish、David J. Lipman及Webb Miller博士开发的。

生信息学?没错,其中的道理与文本比较一回事!!!!

Eugene Myers

Stephen Altschul

David J. Lipman

Webb Miller

以上非 LD 算法是给大家提个醒,用途不同,算法相同,可以写出很多篇论文的。

七、源程序

using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;namespace Legalsoft.Truffer
{public class FileComparer{private int Llen { get; set; } = 0;private int Rlen { get; set; } = 0;private string[] source { get; set; } = null;private string[] current { get; set; } = null;private int[,] CellValue { get; set; } = null;private int[,] CellNumber { get; set; } = null;private int[,] CellDlen { get; set; } = null;private bool IsChanged { get; set; } = false;private List<Point> LineComList { get; set; } = new List<Point>();private List<LineCompareInfo> InfoList { get; set; } = new List<LineCompareInfo>();private StringBuilder sourceBuffer { get; set; } = new StringBuilder();private StringBuilder tagBuffer { get; set; } = new StringBuilder();public FileComparer(){}private string Replace_Special_String(string sourceStr){return sourceStr.Replace(@"\", @"\\").Replace("{", @"\{").Replace("}", @"\}");}/// <summary>/// 比较文件的主函数/// </summary>/// <param name="src">比较文本之一</param>/// <param name="dst">比较文本之二</param>/// <returns>CompareResultString类对象,包含两个文件的Rtf字符串</returns>public CompareResultString Execute(string src, string dst){source = src.Split('\r');current = dst.Split('\r');string[] LstrArray = null;string[] RstrArray = null;if (current.Length > source.Length){IsChanged = true;Llen = current.Length;Rlen = source.Length;LstrArray = current;RstrArray = source;}else{Llen = source.Length;Rlen = current.Length;LstrArray = source;RstrArray = current;}CellValue = new int[Llen + 1, Rlen + 1];CellNumber = new int[Llen + 1, Rlen + 1];CellDlen = new int[Llen + 1, Rlen + 1];for (int i = Llen - 1; i >= 0; i--){for (int j = Rlen - 1; j >= 0; j--){if (LstrArray[i].Trim() == RstrArray[j].Trim()){CellValue[i, j] = 1;CellNumber[i, j] = TripleMax(CellNumber[i + 1, j + 1] + 1, CellNumber[i, j + 1], CellNumber[i + 1, j]);CellDlen[i, j] = CellDlen[i + 1, j + 1] + 1;}else{CellValue[i, j] = Line_String_Compare(LstrArray[i], RstrArray[j]);if (CellValue[i, j] > 0){CellNumber[i, j] = TripleMax(CellNumber[i + 1, j + 1] + 1, CellNumber[i, j + 1], CellNumber[i + 1, j]);if (CellNumber[i, j] == 0){continue;}CellDlen[i, j] = CellDlen[i + 1, j + 1] + 1;}else{CellNumber[i, j] = TripleMax(CellNumber[i + 1, j + 1], CellNumber[i, j + 1], CellNumber[i + 1, j]);if (CellNumber[i, j] == 0){continue;}if (CellNumber[i, j + 1] >= CellNumber[i + 1, j]){CellDlen[i, j] = CellDlen[i, j + 1];}else{CellDlen[i, j] = CellDlen[i + 1, j] + 1;}}}}}// 将比较结构构建为Rtf信息用于Richtext的显示Line_Information_Initialize();Create_Rtf_String();CompareResultString RtfTr = new CompareResultString();RtfTr.LeftRtf = sourceBuffer.ToString();RtfTr.RightRtf = tagBuffer.ToString();return RtfTr;}private int TripleMax(int a, int b, int c){return a > b ? (a > c ? a : c) : (b > c ? b : c);}private void Create_Rtf_String(){foreach (LineCompareInfo infotemp in InfoList){if (infotemp.IsChanged){if (infotemp.CompareDegree == 1){sourceBuffer.Append("\\cf0" + source[infotemp.RightCount]);tagBuffer.Append("\\cf0" + current[infotemp.LeftCount]);}else if (infotemp.CompareDegree == -1){if (infotemp.LeftCount == -1){sourceBuffer.Append("\\cf1");sourceBuffer.Append(source[infotemp.RightCount]);sourceBuffer.Append("\\cf0");}else{tagBuffer.Append("\\cf1");tagBuffer.Append(current[infotemp.LeftCount]);tagBuffer.Append("\\cf0");}}else{Get_Compare_Infomations(source[infotemp.RightCount], current[infotemp.LeftCount]);}}else{if (infotemp.CompareDegree == 1){sourceBuffer.Append("\\cf0" + source[infotemp.LeftCount]);tagBuffer.Append("\\cf0" + current[infotemp.RightCount]);}else if (infotemp.CompareDegree == -1){if (infotemp.LeftCount == -1){tagBuffer.Append("\\cf1");tagBuffer.Append(current[infotemp.RightCount]);tagBuffer.Append("\\cf0");}else{sourceBuffer.Append("\\cf1");sourceBuffer.Append(source[infotemp.LeftCount]);sourceBuffer.Append("\\cf0");}}else{Get_Compare_Infomations(source[infotemp.LeftCount], current[infotemp.RightCount]);}}sourceBuffer.Append("\\par\r\n");tagBuffer.Append("\\par\r\n");}}private List<Point> String_Compare(string sou, string tag){LineComList.Clear();IsChanged = false;char[] lchar = null;char[] rchar = null;if (sou.Length > tag.Length){lchar = sou.ToCharArray();rchar = tag.ToCharArray();}else{IsChanged = true;lchar = tag.ToCharArray();rchar = sou.ToCharArray();}Rlen = lchar.Length;Llen = rchar.Length;CellValue = null;CellNumber = null;CellDlen = null;CellValue = new int[Llen + 1, Rlen + 1];CellNumber = new int[Llen + 1, Rlen + 1];CellDlen = new int[Llen + 1, Rlen + 1];for (int i = Llen - 1; i >= 0; i--){for (int j = Rlen - 1; j >= 0; j--){if (rchar[i] == lchar[j]){CellValue[i, j] = 1;CellNumber[i, j] = TripleMax(CellNumber[i + 1, j + 1] + 1, CellNumber[i, j + 1], CellNumber[i + 1, j]);}else{CellNumber[i, j] = TripleMax(CellNumber[i + 1, j + 1], CellNumber[i, j + 1], CellNumber[i + 1, j]);CellValue[i, j] = 0;}if (CellNumber[i, j] == 0){continue;}if (CellValue[i, j] == 1){CellDlen[i, j] = CellDlen[i + 1, j + 1] + 1;}else{if (CellNumber[i, j + 1] >= CellNumber[i + 1, j]){CellDlen[i, j] = CellDlen[i, j + 1];}else{CellDlen[i, j] = CellDlen[i + 1, j] + 1;}}}}Get_Compare_List(new Point(0, 0));return LineComList;}private void Get_Compare_Infomations(string sou, string tag){int lastx = -1;int lasty = -1;foreach (Point point in String_Compare(sou, tag)){int llen = point.X - lastx - 1;int rlen = point.Y - lasty - 1;if (llen > 0){if (IsChanged){sourceBuffer.Append("\\cf1 ");sourceBuffer.Append(sou.Substring(lastx + 1, llen));sourceBuffer.Append("\\cf0 ");}else{tagBuffer.Append("\\cf1 ");tagBuffer.Append(tag.Substring(lastx + 1, llen));tagBuffer.Append("\\cf0 ");}}if (rlen > 0){if (IsChanged){tagBuffer.Append("\\cf1 ");tagBuffer.Append(tag.Substring(lasty + 1, rlen));tagBuffer.Append("\\cf0 ");}else{sourceBuffer.Append("\\cf1 ");sourceBuffer.Append(sou.Substring(lasty + 1, rlen));sourceBuffer.Append("\\cf0 ");}}if (IsChanged){sourceBuffer.Append(sou[point.X]);tagBuffer.Append(tag[point.Y]);}else{tagBuffer.Append(tag[point.X]);sourceBuffer.Append(sou[point.Y]);}lastx = point.X;lasty = point.Y;}if (IsChanged){if (lasty < tag.Length - 1){tagBuffer.Append("\\cf1 ");tagBuffer.Append(tag.Substring(lasty + 1));tagBuffer.Append("\\cf0 ");}if (lastx < sou.Length - 1){sourceBuffer.Append("\\cf1 ");sourceBuffer.Append(sou.Substring(lastx + 1));sourceBuffer.Append("\\cf0 ");}}else{if (lasty < sou.Length - 1){sourceBuffer.Append("\\cf1 ");sourceBuffer.Append(sou.Substring(lasty + 1));sourceBuffer.Append("\\cf0 ");}if (lastx < tag.Length - 1){tagBuffer.Append("\\cf1 ");tagBuffer.Append(tag.Substring(lastx + 1));tagBuffer.Append("\\cf0 ");}}tagBuffer.Append("\\cf0 ");sourceBuffer.Append("\\cf0 ");}private void Line_Information_Initialize(){Get_Compare_List(new Point(0, 0));int lastlift = -1;int lastright = -1;int linecount = 0;foreach (Point pt in LineComList){if (pt.X - lastlift - pt.Y + lastright > 0){for (int i = 0; i < pt.X - lastlift - 1; i++){if (lastright + 1 + i < pt.Y){this.InfoList.Add(new LineCompareInfo(linecount++, lastlift + 1 + i, lastright + 1 + i, 0, IsChanged));}else{this.InfoList.Add(new LineCompareInfo(linecount++, lastlift + 1 + i, -1, -1, IsChanged));}}}else if (pt.X - lastlift - pt.Y + lastright < 0){for (int i = 0; i < pt.Y - lastright - 1; i++){if (lastlift + 1 + i < pt.X){this.InfoList.Add(new LineCompareInfo(linecount++, lastlift + 1 + i, lastright + 1 + i, 0, IsChanged));}else{this.InfoList.Add(new LineCompareInfo(linecount++, -1, lastright + 1 + i, -1, IsChanged));}}}else{for (int i = 0; i < pt.Y - lastright - 1; i++){this.InfoList.Add(new LineCompareInfo(linecount++, lastlift + 1 + i, lastright + 1 + i, 0, IsChanged));}}this.InfoList.Add(new LineCompareInfo(linecount++, pt.X, pt.Y, CellValue[pt.X, pt.Y], IsChanged));lastlift = pt.X;lastright = pt.Y;}CellValue = null;CellNumber = null;CellDlen = null;LineComList.Clear();}private void Get_Compare_List(Point point){if (point.X < Llen && point.Y < Rlen){if (CellValue[point.X, point.Y] > 0){LineComList.Add(point);Get_Compare_List(new Point(point.X + 1, point.Y + 1));}else{Point NextPoint = Get_Next_Point(point);if (NextPoint != new Point(0, 0)){LineComList.Add(NextPoint);Get_Compare_List(new Point(NextPoint.X + 1, NextPoint.Y + 1));}}}else{return;}}private Point Get_Next_Point(Point point){if (point == new Point(0, 0)){return new Point(0, 0);}Point tempoint = new Point();int TripleMaxD = CellDlen[point.X, point.Y];int CellNumberv = CellNumber[point.X, point.Y];for (int i = point.X; i < Llen; i++){for (int j = point.Y; j < Rlen; j++){if (CellValue[i, j] > 0 && CellNumber[i, j] == CellNumberv){if (CellDlen[i, j] <= TripleMaxD){tempoint.X = i;tempoint.Y = j;}}}}return tempoint;}private int Line_String_Compare(string source, string target){int m = target.Trim().Length;int n = source.Trim().Length;int matchCount = 0;string longStr, shortStr;if (m == 0 || n == 0){return 0;}int k = 0;if (m > n){k = 2 * n / 3 + 1;longStr = target.Trim();shortStr = source.Trim();}else{k = 2 * m / 3 + 1;longStr = source.Trim();shortStr = target.Trim();}int startNo = 0;for (int i = 0; i < shortStr.Length; i++){int tmpNo = longStr.IndexOf(shortStr[i], startNo);if (tmpNo > 0){startNo = tmpNo + 1;matchCount += 1;}if (matchCount > k){return 2;}}if (matchCount > k){return 2;}else{return 0;}}}public class LineCompareInfo{public int LineCount { get; set; } = 0;public int LeftCount { get; set; } = 0;public int RightCount { get; set; } = 0;public int CompareDegree { get; set; } = 0;public bool IsChanged { get; set; } = true;public LineCompareInfo(int line, int left, int right, int info, bool ischang){this.LineCount = line;this.LeftCount = left;this.RightCount = right;this.CompareDegree = info;this.IsChanged = ischang;}}public class CompareResultString{public string LeftRtf { get; set; } = "";public string RightRtf { get; set; } = "";}public class CompareInfo{public int StartIndex { get; set; } = -1;public int EndIndex { get; set; } = -1;public CompareInfo(){}public CompareInfo(int start, int end){StartIndex = start;EndIndex = end;}}
}

C#,深度好文,精致好码,文本对比(Text Compare)算法与源代码相关推荐

  1. C#,茅塞顿开的精致好码,通用型科学计算器的源代码

    文档管理系列技术文章 文档管理系统的核心技术与难点https://blog.csdn.net/beijinghorn/article/details/122426112PB级全文检索(分布式)解决方案 ...

  2. 【Android源码】源码分析深度好文+精编内核解析分享

    阅读Android源码的好处有很多,比如:可以加深我们对系统的了解:可以参考牛人优雅的代码实现:可以从根本上找出一些bug的原因-我们应该庆幸Android是开源的,所有的功能都可以看到实现,所有的b ...

  3. 一文尽览!文本对抗攻击基础、前沿及相关资源

    // 导读 深度学习的安全性问题已经逐渐被学术界.工业界所认识到并且重视,就文本领域而言,垃圾邮件检测.有害文本检测.恶意软件查杀等实用系统已经大规模部署了深度学习模型,安全性对于这些系统尤为重要. ...

  4. 深度好文:阿里巴巴高级专家对组建技术团队的一些思考

    Photo @https://hackernoon.com/ 文 |威视 因为信任,所以简单. 本文是我从2019年1月底接手CRO线NLP算法团队以来,在团队组建.能力建设.以及管理上的一些思考,全 ...

  5. 百度工程师深度好文, 横评3大企业级区块链技术平台

    百度工程师深度好文, 横评3大企业级区块链技术平台! 区块链从独立的技术范式,慢慢扩展到企业区块链的融合范式,是下一代区块链的核心特征.在区块链技术与AI.大数据.云计算技术加速融合的今天,区块链如何 ...

  6. 深度好文:Netflix奈飞微服务架构设计解析

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"书",获取 来源:22j.co/dz54 1 概述 数年来,Netflix 一直是全球 ...

  7. spring 点击保存按钮页面禁用_用一篇深度好文,详解按钮的设计

    本文共 2092 字,预计阅读 10 分钟,记得点击上面的 蓝字 关注我哦- 为了设计更好的用户界面,我们常常需要回顾它的历史和起源.按钮在界面设计中很重要.在物理按钮时期,手指的轻微触碰可以使设备. ...

  8. 将PDF和Gutenberg文档格式转换为文本:生产中的自然语言处理

    Estimates state that 70%–85% of the world's data is text (unstructured data). Most of the English an ...

  9. 深度好文:2018 年 NLP 应用和商业化调查报告

    . 深度好文:2018 年 NLP 应用和商业化调查报告 Debra 阅读数:7650 2019 年 1 月 11 日 近年来,自然语言处理技术已经取得了长足进步,成为应用范围最广泛,也是最为成熟的 ...

最新文章

  1. 盘点 15 个好用的 API 接口管理神器
  2. 基于re模块的计算器
  3. 有python基础先学c还是c+-初学者学python好还是c
  4. Qt 多重继承时 moc 编译出错
  5. 主机路由在计算机中的应用
  6. JavaScript的引入方式
  7. 恒生证券期货行业用户维稳工作指引(二)
  8. 导出标签_如何从系统导出审计要求的日记账
  9. 漫画 | Linux 并发和竞态问题究竟是什么?
  10. mysql的瓶颈_MySQL 瓶颈分析及优化
  11. Wondershare Recoverit for Mac(数据恢复软件)
  12. linux内存基础知识和相关调优方案
  13. PDFlib使用(c++)
  14. PostSql创建用户
  15. html设置背景颜色以及透明度代码,HTML怎么设置背景颜色透明度?
  16. 直播平台常见直播礼物介绍
  17. pyodbc-操作SQLserver
  18. TaobaoSchedule调度管理控制台
  19. 这是我见过最通俗易懂的MES与ERP介绍文章,带你剖析工业4.0!
  20. 使用itext将HTML 生成PDF文件

热门文章

  1. 分布式WLAN全双工链路加权调度算法
  2. discuz php单页,Discuz! X2 自定义单页面最简单方法
  3. Python-mne库使用教程
  4. Disconnected: No supported authentication methods available(server sent: publickey) 的解决办法
  5. C# 博思得 POSTEK 打印机 打码机 SDK 二次开发 指令打印
  6. win10浏览器闪退_win10 ie浏览器闪退
  7. android电视无线同屏,手机连接电视同屏操作方法详解
  8. Anaconda创建虚拟环境时报错 InvalidArchiveError Error with archive D:\\(anaconda的路径)\\pkgs\\vs2015_runtime
  9. 如何在ChemDraw中输入℃温度符号
  10. m4a转mp3方法,m4a转mp3步骤