比较算法(1)
1、介绍
需求:有时候需要比较两个文本,看有什么异同。
- 在渗透过程中分析响应变化很实用,可以快速定位不同区域,比如在xss分析过程,或者定位一次性token
- 另一个场景,是对文件与文件的字节进行比较,用于学习文件结构,以及分析图片木马、加壳、后缀名修改等操作的影响
比较算法,将两个文本分别进行切割成n个子字符串,对应索引的子字符串有四种情况:
- 作为两个文本的共同子字符串
- 文本a有,而文本b无,为空字符串
- 文本a无,为空字符串,而文本b有
- 文本a和文本b都有,但子字符串不同
通过ui组件对上述四种情况,分别进行颜色标记,以便使用者查看。同时还可以输出在此基础上的统计信息:子字符串个数n,各类型的个数,共同子字符串的总字符数,可以用共同子字符串的个数/总字符串个数或者共同子字符串字数之和*2/(a+b的字符数)表示重复率
2、算法实现
算法核心,是找共同子字符串,并且尽可能长。剩下的自动归为另外三类情形。
(1)两个文本,记为a和b。约定共同子字符串的最小字符长度sub_len_min
(2)a_sub_list和b_sub_list分别记为a和b的结果list
(3)a_range是list[int,int]类型,表示a文本中匹配字符串的开始索引的范围,初始为[0,0]。a_range[0]表示上一个子字符串的结束索引,从a_range[1]是。
类似的,定义b_range
(4)循环
- 在a中以a_range[1]作为开始索引,截取长度为sub_len_min的子字符串,即a[a_range[1]: a_range[1]+sub_len_min]
- 在b中从b_range[0]到b_range[1]范围内遍历,是否存在索引为开始索引,长度为sub_len_min的子字符串与a中此时待判断的子字符串相同
- 如果存在相同,则以此为基础,判断是否存在更长的共同子字符串。最终将最长共同子字符添加到a_sub_list和b_sub_list。需要注意,a和b中共同字符串前的非共同子字符串也需要按序添加到a_sub_list和b_sub_list中
- 如果不存在相同,则a_range[1]对自身+1,下一次循环再判断
- 对b重复以上步骤
- 当a_range[1]==len(a)-min_sub_len或者b_range[1]==len(b)-min_sub_len时,不再循环,而是直接将各自的剩余部分作为子字符串添加。
(5)注意,结果中不会出现同一索引在两个list中同时为空字符串
(6)如果只要其中一个为空字符串,或者其中一个的长度小于sub_len_min,那么直接将两个字符串作为各自的子字符串
3、优化1
上述算法可以称之为整体比较,而在某些场景中,存在按行比较的需求,比如html中,结构是相对固定的,即行数相同。这样可以提高比较的准确性
4、优化2
(1)在a和b中找到最大的共同子字符串,将其各分割为三个子字符串
(2)在剩下的部分继续找最大共同子字符串,类似迭代操作