打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
项目介绍之论文格式的自动检测与修改系统

项目背景:此项目隶属于大连理工大学国家级创业训练项目,由三个人负责主要的模块的开发,并交由实验室网站组上线,主要解决高校毕业生论文格式不规范,而人工检查费时费力这一现实问题。

项目内容:此项目的在于检测论文中所有格式错误,并加以修改。可以得到整篇论文的错误格式报告和修改格式后的论文。

通过运用OpenXMLSDK,比较和修改用户上传的论文的XML标签与标准模板XML标签,来达到检测和修改论文格式的目的。截止到目前,这个系统已经在校内网上线,大规模测试了三次,并且已经检测了超过6000篇论文。

我的工作: 负责图,表,页眉页脚等模块的开发,负责字体字号格式检测与修改函数编写。

用到的技术: C#, OpenXMLSDK , XML提取,字符串匹配

成果: 自动检测系统、修改程序各一套,专利、软件著作权各一项

Github: https://github.com/Moflowerszww/PaperFormatDetection

开发的过程分为了以下几个部分:

(1) 研究word论文格式与对应的xml映射关系,利用OpenXML等工具研究word下.doc及.docx文件实现过程中用到的标签、类、库,为提取属性及属性对比打下基础。

(2) 如何从xml中提取格式特征,即利用C#语言提取出每个格式特征的XML标签,并运用到检测过程当中。

(3) 上传的的论文与指定的模板进行对比,须分别提取上传论文与给定模板的同种属性,依次完成所有属性的对比。

(4) 全面且准确的将word论文格式封装进库,拟建立一个新的架构层次,避免对比过程中出现耦合,利于系统后期维护与升级。

主要功能运行

网站首页

检测页面

生成的报告页

修改前后对比图(也有不完美的地方)

结果统计分析页

项目证书

发表论文

申请专利

软件著作权

附一些解释及原理:

OpenXML SDK 简介

Open XML SDK 2.0 for Microsoft Office是微软公司发布的一个的类的集合,使用这些类,开发人员能够操作和新建基于Office Open XML格式标准的Open XML文档。由于SDK能够提供某些让用户可以直接去操作OpenXML文档的应用程序接口,因此在服务器和客户端的操作环境下,即使没有Office客户端产品,用户也能够实现此操作。

docx文档简介

docx是Microsoft Office 2007之后的版本所使用新格式,在过去的的文件扩展名之后增加了字母“x”成为新的后缀名,并使用新的基于XML的压缩文件的格式来代替了其目前特有的默认文件格式。docx格式的文件中的大部分内容是通过XML标准来保存的,但文件并不是保存于磁盘,而是通过一个zip压缩文件保存,并将扩展后缀名改为docx。通过修改docx文件的后缀名为zip并解压,或得到一个名为word的文件夹,其包含了一篇Word文档中的全部内容。Word文件夹下的document.xml文件则包含了文档之中绝大多数的文本内容。使用基于压缩的技术,能够将Word文档所占的内存减少很多。

在docx格式发布之前的doc格式文档是基于二进制存储的,是无法直接转化成为其他格式的,而Office OpenXML格式采用的是zip压缩技术以及XML文本技术。所以与doc格式文档不同之处就在于docx后缀格式的文档能通过修改后缀名为zip进行解压缩,并且可以通过解压缩后的文档看到Word中的各个组件。Word和Excel 07以及之后的版本的Office系统现在已经开始采用这种新的扩展技术了。比如说,后缀名为docx的文档是Word文档基于OpenXML格式生成的文档,把一个doc后缀名的文档升级为docx格式的文档后,通过修改后缀名为zip,然后解压缩,可以得到包含所有XML的文件夹。

操作原理

微软公司在OpenXml的公共开发接口中提出了一种专门用于Word文档的语言,被称为WordprocessingML语言。通过该语言生成的文档被叫做WordprocessingML文档。通过这种的语言所生成的文档通常会包含着两种元素,一个是<.body>,另一个是 document,这两种元素之后则通常会跟着一个或者多个的块级元素,比如<.tab/>,<.p>等,<.p>即表示的是一个段落,一个段落则会存在一个或多个<.r>元素,其表示的是一段连续的文字,这些文本会具有一些相同的属性,所以存在于一个<.r>中。而一段连续的文字则通过<.t>元素来保存其文本内容,一个段落中一般会有一个或多个<.t>元素 。

WordprocessingML和命名空间中的类的对照表

包部分WordprocessingML元素OpenXml SDK中的类说明
主文档documentDocument表示主文档的元素
页脚ftrFooter表示页脚部分的元素
页眉hdrHeader表示页眉部分的元素
文档样式stylesStyles表示样式定义的元素

通过上述表中的内容分析,
Paragraph类表示在当前的XML格式文档之中的段落,并使用<.p>标签来表示,通过使用Paragrapgh类可以而已解析OpenXml文档之中的<.p>标签。在WordprocessingML中,使用段落属性<.pPr>元素来表示段落的属性。段落的属性包括字体、字号、颜色、行距、缩进等。而<.rPr>元素在WordprocessingML中表示的则是文档的运行属性,其与文档的段落属性基本一致。一篇有Word编写的文档在其段落之中通常都会傲寒这大量的文本内容,在WordprocessingML文档所使用的架构中,<.r>元素被用来划分文本块中的那些连续的文字。相对于<.r>元素,<.t>元素则相当于一个容器,代替其保存那些文本化的内容。一段连续的文儿内容通常会有相同的属性,这些属性被称为样式或者格式,使用<.r>元素能够保存这些属性的设置,并将其运用在一段连续文本的整体或者部分之中。每一段连续的文本和段落一样都会有自己的属性,<.r>元素的属性则是通过段落运行属性元素<.rPr>来设置,通过对<.rPr>元素的设置,可以对<.t>元素中保存的文本内容加上例如加粗、下划线、颜色、字体、字号等各种各样的属性。

除去上述的段落之外,WordprocessingML中还有一种同样重要的块级内容就是表,表是通过行和列来描述一个段落的内容块,其在WordprocessingML中通过<.tbl>元素来表示与定义一个表,从拼写上看其与HTML语言中的表格的拼写非常的相似。<.tbl>元素具有两个属性元素,<.tblPr>和<.tblGrid>,<.tblPr>用来表示表所在的范围内的一组属性,比如样式和宽度,<.tblGrid>则用来表示一个表的网格布局。一个<.tbl>元素可以包含一个或多个行,其中每行使用<.tr>元素来表示。每行则又能够包含一个或者多个的表格列,列使用<.td>元素表示。行和列的交汇被称之为单元格,单元格我们使用<.tc>表示。通过使用OpenXML SDK Tool 查看多篇文档之后,总结得到了如表5.3中所表示的对应关系。

WordprocessingML表格元素和类的对应关系

WordprocessingML元素OpenXML SDK中的类
tr tblPr gridColTableRow TableProperties GridColum
tblGridTableGrid
tcTableCell

WordprocessingML文档之中,使用<.tbl >元素来定义一个表格,通过视同Table事项,我们能够使用代码来完成对一个表格的操作。每一个表格都有几个部分组成:行、列、单元格、表格属性以及网格属性。在上表中我们能够看到<.tr>元素被用来表示一个表格的行,通过获取表格中TableRow成员,我们可得到一个表格中的各个行。而<.tblPr>元素在WordprocessingML中被定义表示一个表格的表格属性,其通常包含了一个表格的是否具有某个边框,边框的线粗,以及表格的位置板式等属性,在代码里通过获取表格的TableProperties成员,我们就能得到一个表格的上述属性。<.gridCol>元素在WordprocessingML中定义为表格行,其表示的是表格的行的通用设置属性。通过实例化获取一个表格中的GridColum成员,我们就能实现对一个表格行的操作。一个<.tbl>元素可以包含一个或多个行,其中每行使用<.tr>元素来表示。每行则又能够包含一个或者多个的表格列,列使用<.td>元素表示。行和列的交汇被称之为单元格,单元格我们使用<.tc>表示。

页眉定位算法

<.hdr>元素存储了标题的文本信息以及样式。需要注意的是OpenXML中的页眉不是和我们直接打开文档看到的各页的页眉一一对应的。OpenXML中根据文档设置的各个节【参考文献】的页眉属性如首页不同、奇偶页不同生成相应的页眉。这里的节由OpenXML中的< sectPr>属性体现:每一节的最后都会有一个<.sectPr>属性,这个属性存储此节的页眉的类型和ID、页脚的类型和ID、页的大小宽度、页边距、网格线信息等。根据< sectPr>的ID寻找到这一节对应的< hdr>元素,如首页页眉、奇数页页眉、偶数页页眉。

目录定位算法

目录共包含更新域处理过的目录和未经更新域处理的目录。更新域处理过的目录包含Hyperlinkd标签来标记更新域的位置,该更新域的位置即为目录。未经更新域处理的目录包含FieldChar标签,该标签标记了目录所在的位置。

公式定位算法

元素存储了word文档中一系列其他office软件引入的内容,如公式编辑器编辑的公式,visio编辑的视图等。定位公式首先要找出所有的元素,然后根据公式的格式进行筛选。

(1) 段落属性提取

在OpenXML中,所有文本内容都保存在 < p>中,在表2.1中给出了段落中常见的元素及其说明。

表1 常见的段落元素和C#类明说明

段落元素C#类说明
spacingDocument表示段落间距的元素
indIndentation表示段落缩进的元素
szFontSize表示字体大小的元素
rFontsRunFonts表示字体样式的元素
tText表示段落文本的元素

为了提高编程效率,提高代码的复用率,将段落各个属性的提取封装在工具类函数中,可以方便其它模块使用。如下三点分别详细地描述了段落字体、字号等属性的提取方法。

1.字体

< rFonts>指出了< r>元素中的文本的字体样式,该元素有ASCII、High ANSI、Complex Scipt、East Asian等属性,在本系统中仅检测ASCII及East Asian属性。

ASCII记录ASCII码值在0-127之间的字符字体,如26个大小写英文字母、常见的符号,详情见ASCII码表。East Asian记录UNICODE码值在东亚范围内的字符字体,如汉字、日本语等。论文对中英文字体有不同要求,例如要求中文为宋体,则East Asian应等于“宋体”,要求英文为Times New Roman,则ASCII应等于“Times New Roman”。

按照样式的层次结构依次提取字体样式,就可以获取到中英文的字体,但需要注意的是,有时段落中并没有英文字体,但是却提取到了英文字体的样式,此时应该增加一个判断,判断段落中实际的字符情况:是全英文、全中文还是中英文兼有。

2.字号

< sz>指出了< r>元素中的文本< t>的字号样式。< sz>的属性Val的值代表了字号的大小,如<w:sz w:val=”24”/>代表字号为24/2=12磅。查询字号对照表【参考文献】得到字号和磅数的对应关系,就可以得到实际的字号为“小四”。

3.段前间距、段后间距和行距

< pPr>的子元素< spacing>存储此段落的间隔样式,如段前距离before、beforeLines,段后距离after、afterLines,行间距lineRule、line。

段前距样式信息由before和beforeLines存储。如语句<w:spacing w:after=”200” />说明段前距离为200/20=20磅。<w:spacing w:afterLines=”300” />说明段前距离为300/100=3行。当两者同时出现时before属性应被忽略。

利用< sectPr>元素的子元素< docGrid>的linePitch属性可以获得一行的磅数,如:从<w:docGrid w:linePitch=”326” w:charSpace=”-2048” />可知,一行为326/ 20=16.3磅。这样就可以解决单位不一致带来的麻烦,统一换算成以“磅”为单位的数据。段后间距和段前间距类似。

行距样式信息由lineRule和line提取。lineRule保存的是解析line的方法。若lineRule=auto或者省略,如:<w:spacing w:line=”276” w:lineRule=”auto” />,则行间距为276/240=1.15倍行距。若lineRule= atLeast(最小值)或者exactly(固定值),如:<w:spacing w:line=”200” w:lineRule=”exactly” />,则行间距为200/20=10磅。

4.参考文献样式提取中正则表达式的应用

常见的参考文献类型有专著[M]、论文集[C]、期刊文章[J]、学位论文[D]、专利[P]等,不同类型的参考文献规定格式不同,因此需要先确定每条参考文献属于哪种参考文献,然后才能进行具体的格式分析,在参考文献类型确定以及具体分析中正则表达式都有着很大的作用,在表2中列出了参考文献模块中应用的正则表达式并做出相应的说明:

表2 参考文献模块中正则表达式的应用

正则表达式说明
Match letter = Regex.Match(paraText, @”[A-Z?]“)匹配字符串paraText中的字母标识,如“[M]”
Match number = Regex.Match(paraText, @”[\d+]“)匹配字符串paraText中的数字编号,如“[12]”,进而判定编号的正确性
string[] textArr = Regex.Split(paraText, @”[\w*]“)用中括号把参考文献条目paraText分割成几个小字符串,进而对各个小字符串进行处理
Bool isChinese=Regex.IsMatch(paraText, @”[\u4e00-\u9fa5]”)判断字符串paraText中是否有中文,进而判定是中文参考文献还是英文参考文献
Match year = Regex.Match(textArr[1], @”[1-2][0-9][0-9][0-9]”)匹配字符串textArr[1]中的期刊年份,如“2006”

参考文献编号连续性

在OpenXML中有自动编号的功能,当某个编号为自动编号时,生成的标签如下所示。

1
2
3
4
5
6
w:pPr>
<w:numPr>
<w:ilvl w:val='0' />
<w:numId w:val='1' />
</w:numPr>
</w:pPr

其中< ilvl>指出了编号的层级为第0层,< numId>指出了编号的Id,根据Id倒着寻找中属性等于numId的< num>,在< num>元素中有子元素< abstractNumId>,接着寻找与< abstractNumId>的Val值相等的< abstractNum>就可以得到该编号的属性。如从<w:start w:val=”1” />可以得到该编号是从1开始的,从<w:lvlText w:val=”%1.” />可以看出该编号的样式。

由此可以分析< numId>一样的连续段落,编号一定是连续的。但是在实际的论文中,自动编号和手动编号可能是掺杂着的。因此需要确定每一条参考文献的正确序号,手动编号的参考文献直接比对。而自动编号的段落只需要检查第一个自动编号的段落的序号是否正确即可。

简单操作代码 demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
Body body = doc.MainDocumentPart.Document.Body;
MainDocumentPart mainPart = doc.MainDocumentPart;
IEnumerable<Paragraph> paras = body.Elements<Paragraph>();
StyleDefinitionsPart stylePart = mainPart.StyleDefinitionsPart;
Styles styles = stylePart.Styles;
var t = styles.ChildElements;
RunProperties rPr = null;
ParagraphProperties pPr = null;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlFullPath);
XmlNode root = xmlDoc.SelectSingleNode('CoverStyle/Title');
int count = 0;
foreach (Paragraph p in paras)
{
Run r = p.GetFirstChild<Run>();
if (r == null) continue;
Text text = r.GetFirstChild<Text>();
if (text.Text != null && text.Text.Replace(' ', '') != '')
{
count++;
if (count == 1)
{
rPr = r.GetFirstChild<RunProperties>();
pPr = p.GetFirstChild<ParagraphProperties>();
bool rfflag = false;
bool fzflag = false;
bool bflag = false;
XmlElement xesub = xmlDoc.CreateElement('Heading');
xesub.SetAttribute('name', '论文大标题');
XmlElement xesub1 = xmlDoc.CreateElement('Text');
xesub1.InnerText = tool.getFullText(p).Replace(' ','');
xesub.AppendChild(xesub1);
if(rPr != null)
{
//字体
if (rPr.GetFirstChild<RunFonts>() != null)
{
if (rPr.GetFirstChild<RunFonts>().Ascii != null)
{
rfflag = true;
XmlElement xe1 = xmlDoc.CreateElement('Fonts');
xe1.InnerText = rPr.GetFirstChild<RunFonts>().Ascii;
xesub.AppendChild(xe1);

}
}
//字号
if (rPr.GetFirstChild<FontSize>() != null)
{
if (rPr.GetFirstChild<FontSize>().Val != null)
{
fzflag = true;
XmlElement xe1 = xmlDoc.CreateElement('size');
xe1.InnerText = rPr.GetFirstChild<FontSize>().Val.Value;
xesub.AppendChild(xe1);
}
}
}
if(pPr != null)
{
//对齐方式
if (pPr.GetFirstChild<Justification>() != null)
{
XmlElement xe1 = xmlDoc.CreateElement('jc');
xe1.InnerText=pPr.GetFirstChild<Justification>().Val.
Value.ToString().ToLower();
xesub.AppendChild(xe1);
}
}
root.AppendChild(xesub);
break;
}
}
}
xmlDoc.Save(xmlFullPath);

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Word论文排版
电脑高手必备:Word使用技巧放送 [和讯博客]
word 操作全教程
Word文档中直线的多种属性——如何有效解决电子公文中的直线问题
创建和使用 Word 文档中的内容构建基块
如何删除WORD文档页眉及页脚处单实线
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服