前言
我们在写论文的时候,为了避免论文重复,可以使用第三方的库进行查重。但是,有时候在写论文的时候,只是引用自己之前的资料,在查重前想对自己的论文两篇文章进行查重。网上找了一下,没找到合适的工具,于是就自己用Python写了一个。
基本思路
两篇论文查重的方法相对比较简单,即将文章拆分成小句,然后小句间进行两两对比。主要实现基本可以分为以下三步:
- 读取
使用Python的python-docx库,可以非常方便的读取Word的内容,具体可以参见官方文档,网上也有很多不错的文章请自行查询参考。 - 原文拆分
对比的基本思想是按小句进行比较,所以拆分以是标点,即,。?!
等进行拆分。拆分完成以后,可以有很多的小段。本文中为了便于定位,先根据原始段落进行拆分,然后再将每段根据标点拆分成若干小句,即一个word文档 = [[段落1], [段落2], [段落3], ...,[段落n]]
,而每个段落= [[小句1],[小句2],[小句3],...,[小句m],]
。 - 循环对比输出
第三步就是根据段落,两两进行对比,遇到匹配输出结果。
在对比中,有几点要注意:
- 如果子句过短(长度<5)则忽略,因为这种情况都是名词或术语,允许重复。
- 两个子句比较时,并不是用等号,而用包括,即一个子句是否包含另一个子句。
实现代码
# coding=utf-8
from docx import Document
import re, sys, datetime
def getText(wordname):
d = Document(wordname)
texts = []
for para in d.paragraphs:
texts.append(para.text)
return texts
def is_Chinese(word):
for ch in word:
if '\u4e00' <= ch <= '\u9fff':
return True
return False
def msplit(s, seperators = ',|\.|\?|,|。|?|!'):
return re.split(seperators, s)
def readDocx(docfile):
print('*' * 80)
print('文件', docfile, '加载中……')
t1 = datetime.datetime.now()
paras = getText(docfile)
segs = []
for p in paras:
temp = []
for s in msplit(p):
if len(s) > 2:
temp.append(s.replace(' ', ""))
if len(temp) > 0:
segs.append(temp)
t2 = datetime.datetime.now()
print('加载完成,用时: ', t2 - t1)
showInfo(segs, docfile)
return segs
def showInfo(doc, filename = 'filename'):
chars = 0
segs = 0
for p in doc:
for s in p:
segs = segs + 1
chars = chars + len(s)
print('段落数: {0:>8d} 个。'.format(len(doc)))
print('短句数: {0:>8d} 句。'.format(segs))
print('字符数: {0:>8d} 个。'.format(chars))
def compareParagraph(doc1, i, doc2, j, min_segment = 5):
"""
功能为比较两个段落的相似度,返回结果为两个段落中相同字符的长度与较短段落长度的比值。
:param p1: 行
:param p2: 列
:param min_segment = 5: 最小段的长度
"""
p1 = doc1[i]
p2 = doc2[j]
len1 = sum([len(s) for s in p1])
len2 = sum([len(s) for s in p2])
if len1 < 10 or len2 < 10:
return []
list = []
for s1 in p1:
if len(s1) < min_segment:
continue;
for s2 in p2:
if len(s2) < min_segment:
continue;
if s2 in s1:
list.append(s2)
elif s1 in s2:
list.append(s1)
# 取两个字符串的最短的一个进行比值计算
count = sum([len(s) for s in list])
ratio = float(count) / min(len1, len2)
if count > 10 and ratio > 0.1:
print(' 发现相同内容 '.center(80, '*'))
print('文件1第{0:0>4d}段内容:{1}'.format(i + 1, p1))
print('文件2第{0:0>4d}段内容:{1}'.format(j + 1, p2))
print('相同内容:', list)
print('相同字符比:{1:.2f}%\n相同字符数: {0}\n'.format(count, ratio * 100))
return list
if len(sys.argv) < 3:
print("参数小于2.")
doc1 = readDocx(sys.argv[1])
doc2 = readDocx(sys.argv[2])
print('开始比对...'.center(80, '*'))
t1 = datetime.datetime.now()
for i in range(len(doc1)):
if i % 100 == 0:
print('处理进行中,已处理段落 {0:>4d} (总数 {1:0>4d} ) '.format(i, len(doc1)))
for j in range(len(doc2)):
compareParagraph(doc1, i, doc2, j)
t2 = datetime.datetime.now()
print('\n比对完成,总用时: ', t2 - t1)
测试结果
测试文章两篇,均为来自于百度文库):《新交通法规2016全文》 和 《新交通法规牌照细则》。
运行命令
> python wordProcess.py d:\jg2016.docx d:\jg2017.docx
对比结果如下。
********************************************************************************
文件 d:\jg2016.docx 加载中……
加载完成,用时: 0:00:00.012992
段落数: 312 个。
短句数: 846 句。
字符数: 15703 个。
********************************************************************************
文件 d:\jg2017.docx 加载中……
加载完成,用时: 0:00:00.004016
段落数: 145 个。
短句数: 379 句。
字符数: 6509 个。
************************************开始比对...*************************************
处理进行中,已处理段落 0 (总数 0312 )
处理进行中,已处理段落 100 (总数 0312 )
************************************ 发现相同内容 ************************************
文件1第0137段内容:['\u3000\u3000机动车运载超限的不可解体的物品', '影响交通安全的', '应当按照公安机关交通管理部门指定的 时间、路线、速度行驶', '悬挂明显标志', '在公路上运载超限的不可解体的物品', '并应当依照公路法的规定执行']
文件2第0090段内容:['高速公路是绝对的危险路段', '由于高速公路是全封闭的设计', '所以您在高速路上只能是向前跑', '出现停车 、倒车甚至是逆行和借助中央隔离带的缺口掉头等行为', '都是严重影响交通安全的', '以上行为都会受到12分的处罚', '以上均为严重影响交通安全的恶劣行为', '除了原来的6项之外有增加了5项', '部分为6分的处罚规定升级的12分', '针对我国的情况来看', '有助于 更好地把控违章行为', '安全意识不够高也只能用提高处罚的力度来维护交通环境了', '而对于牡丹卡中的分值来说', '一次性扣除12分是最严厉的处罚了']
相同内容: ['影响交通安全的', '影响交通安全的']
相同字符比:16.28%
相同字符数: 14
************************************ 发现相同内容 ************************************
文件1第0138段内容:['\u3000\u3000机动车载运爆炸物品、易燃易爆化学物品以及剧毒、放射性等危险物品', '应当经公安机关批准后', '按指定的时间、路线、速度行驶', '悬挂警示标志并采取必要的安全措施']
文件2第0116段内容:['驾驶机动车运载超限的不可解体的物品', '未按指定的时间、路线、速度行驶或者未悬挂明显标志者', '将受到 扣除6分的处罚']
相同内容: ['按指定的时间、路线、速度行驶']
相同字符比:26.92%
相同字符数: 14
************************************ 发现相同内容 ************************************
文件1第0138段内容:['\u3000\u3000机动车载运爆炸物品、易燃易爆化学物品以及剧毒、放射性等危险物品', '应当经公安机关批准后', '按指定的时间、路线、速度行驶', '悬挂警示标志并采取必要的安全措施']
文件2第0118段内容:['驾驶机动车载运爆炸物品、易燃易爆化学物品以及剧毒、放射性等危险物品', '未按指定的时间、路线、速度行 驶或者未悬挂警示标志并采取必要的安全措施者将受到此处罚']
相同内容: ['按指定的时间、路线、速度行驶', '悬挂警示标志并采取必要的安全措施']
相同字符比:41.10%
相同字符数: 30
处理进行中,已处理段落 200 (总数 0312 )
************************************ 发现相同内容 ************************************
文件1第0212段内容:['\u3000\u3000醉酒驾驶机动车的', '由公安机关交通管理部门约束至酒醒', '吊销机动车驾驶证', '依法追究刑 事责任;五年内不得重新取得机动车驾驶证']
文件2第0023段内容:['依法追究刑事责任', '一律吊销机动车驾驶证']
相同内容: ['吊销机动车驾驶证', '依法追究刑事责任']
相同字符比:88.89%
相同字符数: 16
************************************ 发现相同内容 ************************************
文件1第0214段内容:['\u3000\u3000醉酒驾驶营运机动车的', '由公安机关交通管理部门约束至酒醒', '吊销机动车驾驶证', '依法追 究刑事责任;十年内不得重新取得机动车驾驶证', '重新取得机动车驾驶证后', '不得驾驶营运机动车']
文件2第0023段内容:['依法追究刑事责任', '一律吊销机动车驾驶证']
相同内容: ['吊销机动车驾驶证', '依法追究刑事责任']
相同字符比:88.89%
相同字符数: 16
************************************ 发现相同内容 ************************************
文件1第0215段内容:['\u3000\u3000饮酒后或者醉酒驾驶机动车发生重大交通事故', '构成犯罪的', '依法追究刑事责任', '并由公安 机关交通管理部门吊销机动车驾驶证', '终生不得重新取得机动车驾驶证']
文件2第0025段内容:['一律吊销机动车驾驶证', '终生不得重新取得机动车驾驶证']
相同内容: ['终生不得重新取得机动车驾驶证']
相同字符比:58.33%
相同字符数: 14
************************************ 发现相同内容 ************************************
文件1第0216段内容:['\u3000\u3000第九十二条\u3000公路客运车辆载客超过额定乘员的', '处二百元以上五百元以下罚款;超过额定 乘员百分之二十或者违反规定载货的', '处五百元以上二千元以下罚款']
文件2第0035段内容:['机动车驾驶人补领机动车驾驶证后', '继续使用原机动车驾驶证的', '处二十元以上二百元以下罚款;在实习期内驾驶机动车不符合第六十五条规定的', '处二十元以上二百元以下罚款;驾驶机动车未按规定粘贴、悬挂实习标志或者残疾人机动车专用 标志的', '处二十元以上二百元以下罚款;持有大型客车、牵引车、城市公交车、中型客车、大型货车驾驶证的驾驶人', '未按照规定申 报变更信息的', '处二十元以上二百元以下罚款;机动车驾驶证被依法扣押、扣留或者暂扣期间', '采用隐瞒、欺骗手段补领机动车驾驶 证的', '处二百元以上五百元以下罚款;机动车驾驶人身体条件发生变化不适合驾驶机动车', '仍驾驶机动车的', '处二百元以上五百元 以下罚款;逾期不参加审验仍驾驶机动车的', '处二百元以上五百元以下罚款']
相同内容: ['处二百元以上五百元以下罚款']
相同字符比:18.57%
相同字符数: 13
************************************ 发现相同内容 ************************************
文件1第0217段内容:['\u3000\u3000货运机动车超过核定载质量的', '处二百元以上五百元以下罚款;超过核定载质量百分之三十或者 违反规定载客的', '处五百元以上二千元以下罚款']
文件2第0035段内容:['机动车驾驶人补领机动车驾驶证后', '继续使用原机动车驾驶证的', '处二十元以上二百元以下罚款;在实习期内驾驶机动车不符合第六十五条规定的', '处二十元以上二百元以下罚款;驾驶机动车未按规定粘贴、悬挂实习标志或者残疾人机动车专用 标志的', '处二十元以上二百元以下罚款;持有大型客车、牵引车、城市公交车、中型客车、大型货车驾驶证的驾驶人', '未按照规定申 报变更信息的', '处二十元以上二百元以下罚款;机动车驾驶证被依法扣押、扣留或者暂扣期间', '采用隐瞒、欺骗手段补领机动车驾驶 证的', '处二百元以上五百元以下罚款;机动车驾驶人身体条件发生变化不适合驾驶机动车', '仍驾驶机动车的', '处二百元以上五百元 以下罚款;逾期不参加审验仍驾驶机动车的', '处二百元以上五百元以下罚款']
相同内容: ['处二百元以上五百元以下罚款']
相同字符比:20.63%
相同字符数: 13
************************************ 发现相同内容 ************************************
文件1第0221段内容:['\u3000\u3000机动车驾驶人不在现场或者虽在现场但拒绝立即驶离', '妨碍其他车辆、行人通行的', '处二十元 以上二百元以下罚款', '并可以将该机动车拖移至不妨碍交通的地点或者公安机关交通管理部门指定的地点停放', '公安机关交通管理部门拖车不得向当事人收取费用', '并应当及时告知当事人停放地点']
文件2第0035段内容:['机动车驾驶人补领机动车驾驶证后', '继续使用原机动车驾驶证的', '处二十元以上二百元以下罚款;在实习期内驾驶机动车不符合第六十五条规定的', '处二十元以上二百元以下罚款;驾驶机动车未按规定粘贴、悬挂实习标志或者残疾人机动车专用 标志的', '处二十元以上二百元以下罚款;持有大型客车、牵引车、城市公交车、中型客车、大型货车驾驶证的驾驶人', '未按照规定申 报变更信息的', '处二十元以上二百元以下罚款;机动车驾驶证被依法扣押、扣留或者暂扣期间', '采用隐瞒、欺骗手段补领机动车驾驶 证的', '处二百元以上五百元以下罚款;机动车驾驶人身体条件发生变化不适合驾驶机动车', '仍驾驶机动车的', '处二百元以上五百元 以下罚款;逾期不参加审验仍驾驶机动车的', '处二百元以上五百元以下罚款']
相同内容: ['处二十元以上二百元以下罚款', '处二十元以上二百元以下罚款', '处二十元以上二百元以下罚款', '处二十元以上二百 元以下罚款']
相同字符比:41.94%
相同字符数: 52
************************************ 发现相同内容 ************************************
文件1第0245段内容:['\u3000\u3000对驾驶前款所列机动车上道路行驶的驾驶人', '处二百元以上二千元以下罚款', '并吊销机动车驾 驶证']
文件2第0018段内容:['对上道路行驶的拼装、改装或者应该报废的机动车一律予以收缴', '强制报废', '对驾驶前款所列机动车上道路 行驶的驾驶人', '一律处1500元罚款', '并吊销机动车驾驶证']
相同内容: ['对驾驶前款所列机动车上道路行驶的驾驶人', '并吊销机动车驾驶证']
相同字符比:65.12%
相同字符数: 28
************************************ 发现相同内容 ************************************
文件1第0248段内容:['\u3000\u3000造成交通事故后逃逸的', '由公安机关交通管理部门吊销机动车驾驶证', '且终生不得重新取得机 动车驾驶证']
文件2第0025段内容:['一律吊销机动车驾驶证', '终生不得重新取得机动车驾驶证']
相同内容: ['终生不得重新取得机动车驾驶证']
相同字符比:58.33%
相同字符数: 14
处理进行中,已处理段落 300 (总数 0312 )
比对完成,总用时: 0:00:00.118681
小结
经测试,本方法可以有效地识别出相同的内容, 加满解决了之前的需求,达到了预期的目标。