答:我是根据大纲视图以及正文部分的特征去定位位置的,每一部分内容的开始都需要设置大纲视图级别,例如目录、结论等需要设置为一级。而对于正文部分中,一级标题都需要设置为一级(例如,第一章 绪论需要设置为一级),获取论文中大纲级别的代码如下:
/**
* Word中的大纲级别,可以通过getPPr().getOutlineLvl()直接提取,但需要注意,Word中段落级别,通过如下三种方式定义:
* 1、直接对段落进行定义;
* 2、对段落的样式进行定义;
* 3、对段落样式的基础样式进行定义。
* 因此,在通过“getPPr().getOutlineLvl()”提取时,需要依次在如上三处读取。
* @param doc
* @param para
* @return
*/
public static String getTitleLvl(XWPFDocument doc, XWPFParagraph para) {
String titleLvl = "";
try {
// 判断该段落是否设置了大纲级别
if (para.getCTP().getPPr().getOutlineLvl() != null) {
return String.valueOf(para.getCTP().getPPr().getOutlineLvl().getVal());
}
} catch (Exception e) {
}
try {
// 判断该段落的样式是否设置了大纲级别
if (doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl() != null) {
return String.valueOf(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
}
} catch (Exception e) {
}
try {
// 判断该段落的样式的基础样式是否设置了大纲级别
if (doc.getStyles().getStyle(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal())
.getCTStyle().getPPr().getOutlineLvl() != null) {
String styleName = doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal();
return String.valueOf(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
}
} catch (Exception e) {
}
try {
if(para.getStyleID()!=null){
return para.getStyleID();
}
} catch (Exception e) {
}
return titleLvl;
}
获取大纲级别为一级的段落后,然后根据正文部分的特征定位位置,我的方法是:段落中的文字包含第一章。当满足以上两个条件,则可以判断该段落为第一章一级标题,并且也是正文部分的开始位置。那么如何确定正文段落的范围呢?我的方法是:正文中的一级标题中的文字中包含标题序号,例如第一章、第二章等等。因此,我是根据大纲级别为一级的段落,并且段落中文字是否包含“第”和“章”这两个字,以上两种条件确定是否属于正文段落范围,当不满足条件时,便不是。
答:我的方法是:首先定位一级标题的,然后是二级标题,再然后是三级标题(我只对一级、二级以及三级标题进行校验,四级以及五级标题跟正文段落格式相同,不进行校验)。首先获取大纲级别为一级的段落,然后判断这些段落是否满足正文部分一级标题的特征,代码如下:
// 是否满足一级标题的特征
public static Boolean isFirstTitle(XWPFParagraph para) {
if (para.getParagraphText().indexOf("第") != -1 && para.getParagraphText().indexOf("章") != -1) {
return true;
}
return false;
}
满足以上两个条件,便可以判断为一级标题的段落,同时根据段落的顺序,可以获取正确的标题序号(例如某个段落为第二个一级标题,则该标题序号为第二章)。定位二级以及三级标题与之类似(二级标题段落的大纲级别为二级,三级标题段落的大纲级别为三级)。
答:以下是对字体属性的校验方法(包括中英文字体大小、字体主题、字体加粗):
1、判断文字是中文还是英文的代码如下:
// 对空格、符合、数字不区分中英文
public String removeExtraString(String str){
return str.replaceAll(" ", "")
.replaceAll("[\\pP\\p{Punct}]","")
.replaceAll("[0-9]*", "");
}
// 判断是否英文
public Boolean isEnglishFont(XWPFRun xwpfRun) {
if (this.removeExtraString(xwpfRun.getText(0)).matches("[a-zA-Z]+")){
return true;
}
return false;
}
// 判断是否中文
public Boolean isChinessFont(XWPFRun xwpfRun){
Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
if (pattern.matcher(this.removeExtraString(xwpfRun.getText(0))).find()){
return true;
}
return false;
}
2、获取字体大小的代码如下:
// 获取文档默认字体大小
public float getDocxDefaultFontSize(XWPFDocument docx) throws Exception {
if (docx.getStyle().getDocDefaults().getRPrDefault() != null) {
if (docx.getStyle().getDocDefaults().getRPrDefault().getRPr() != null) {
CTRPr rPr = docx.getStyle().getDocDefaults().getRPrDefault().getRPr();
if (rPr.getSz() != null) {
return (float) rPr.getSz().getVal().longValue()/2;
} else if (rPr.getSzCs() != null) {
return (float) rPr.getSzCs().getVal().longValue()/2;
}
}
}
return 10;
}
// 获取字体大小
public float getFontSize(XWPFDocument docx, XWPFParagraph paragraph, XWPFRun x) throws Exception {
if (x.getCTR().getRPr() != null) {
if (x.getCTR().getRPr().getSz() != null) {
return (float)x.getCTR().getRPr().getSz().getVal().longValue()/2;
} else if (x.getCTR().getRPr().getSzCs() != null) {
return (float)x.getCTR().getRPr().getSzCs().getVal().longValue()/2;
}
}
if (docx.getStyles().getStyle(paragraph.getStyleID()) != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getRPr() != null) {
CTRPr rPr = docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getRPr();
if (rPr.getSz() != null) return (float)rPr.getSz().getVal().longValue()/2;
else if (rPr.getSzCs() != null) return (float)rPr.getSzCs().getVal().longValue()/2;
}
}
// 文档默认字体大小
float fontSize = this.getDocxDefaultFontSize(docx);
return fontSize;
}
3、获取字体主题的代码如下:
// 获取字体的字体主题
public String getFontTheme(XWPFRun run, XWPFDocument docx, XWPFParagraph paragraph) throws Exception {
if (run.getCTR().getRPr() != null && run.getCTR().getRPr().getRFonts() != null) {
CTFonts rFonts = run.getCTR().getRPr().getRFonts();
if (this.isEnglishFont(run) && rFonts.getAscii() != null) {
return rFonts.getAscii();
} else if (this.isChinessFont(run) && rFonts.getEastAsia() != null) {
return rFonts.getEastAsia();
}
}
if (docx.getStyles().getStyle(paragraph.getStyleID()) != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getRPr() != null){
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getRPr().getRFonts() != null) {
CTFonts rFonts1 = docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getRPr().getRFonts();
if (this.isEnglishFont(run) && rFonts1.getAscii() != null) return rFonts1.getAscii();
else if (this.isChinessFont(run) && rFonts1.getEastAsia() != null) return rFonts1.getEastAsia();
}
}
}
// 默认字体主题
String fontTheme = "";
// 如果为英文字体
if (this.isEnglishFont(run)) {
fontTheme = docx.getStyle().getDocDefaults().getRPrDefault().getRPr().getRFonts().getAscii();
} else {
fontTheme = docx.getStyle().getDocDefaults().getRPrDefault().getRPr().getRFonts().getEastAsia();
}
return fontTheme;
}
4、获取字体加粗状态的代码如下:
// 获取默认字体加粗
public Boolean getDocxDefaultFontBold(XWPFDocument docx) throws Exception {
if (docx.getStyle().getDocDefaults().getRPrDefault() != null) {
if (docx.getStyle().getDocDefaults().getRPrDefault().getRPr() != null) {
CTRPr rPr = docx.getStyle().getDocDefaults().getRPrDefault().getRPr();
if (rPr.getB() != null) {
if (rPr.getB().isSetVal()) return false;
else return true;
} else if (rPr.getBCs() != null) {
if (rPr.getBCs().isSetVal()) return false;
else return true;
}
}
}
return false;
}
// 获取字体是否加粗
public Boolean getFontBold(XWPFDocument docx, XWPFParagraph paragraph, XWPFRun run) throws Exception {
if (run.getCTR().getRPr() != null) {
if (run.getCTR().getRPr().getB() != null) {
if (run.getCTR().getRPr().getB().isSetVal()) return false;
else return true;
}
}
if (docx.getStyles().getStyle(paragraph.getStyleID()) != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getRPr() != null) {
CTRPr rPr = docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getRPr();
if (rPr.getB() != null) {
if (rPr.getB().isSetVal()) return false;
else return true;
} else if (rPr.getBCs() != null) {
if (rPr.getBCs().isSetVal()) return false;
else return true;
}
}
}
// 默认字体加粗状态
return this.getDocxDefaultFontBold(docx);
}
以下是对段落属性的校验方法(包括段落行距、首行缩进、段落对齐方式):
1、获取段落首行缩进的代码:
// 获取文档默认首行缩进
public Integer getDocxFirstLineChars(XWPFDocument docx) throws Exception {
if (docx.getStyle().getDocDefaults().getPPrDefault() != null && docx.getStyle().getDocDefaults().getPPrDefault().getPPr() != null) {
CTPPr pPr = docx.getStyle().getDocDefaults().getPPrDefault().getPPr();
if (pPr.getInd() != null && pPr.getInd().isSetFirstLineChars()) {
return pPr.getInd().getFirstLineChars().intValue();
}
}
return -1;
}
// 获取段落首行缩进
public Integer getParaFirstLineChars(XWPFDocument docx, XWPFParagraph paragraph) throws Exception {
if (paragraph.getCTP().getPPr() != null){
if (paragraph.getCTP().getPPr().getInd() != null && paragraph.getCTP().getPPr().getInd().isSetFirstLineChars()) {
return paragraph.getCTP().getPPr().getInd().getFirstLineChars().intValue();
}
}
if (docx.getStyles().getStyle(paragraph.getStyleID()) != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr() != null) {
CTPPr pPr = docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr();
if (pPr.getInd() != null && pPr.getInd().isSetFirstLineChars()) {
return pPr.getInd().getFirstLineChars().intValue();
}
}
}
return this.getDocxFirstLineChars(docx);
}
2、获取段前行距的代码(分为段前行数和段前磅数):
① 获取段前行数的代码:
public Integer getParaSpacingBeforeLines(XWPFParagraph paragraph, XWPFDocument docx) throws Exception {
if (paragraph.getSpacingBeforeLines() != -1) {
return paragraph.getSpacingBeforeLines();
}
if (docx.getStyles().getStyle(paragraph.getStyleID()) != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr() != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing() != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing().getBeforeLines() != null) {
return docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing().getBeforeLines().intValue();
}
}
}
}
// 文档默认段前行距
Integer beforeLines = this.getDocxDefaultSpacing(docx, ThesisConstant.SPACING_BEFORE_Line);
return beforeLines;
}
② 获取段前磅数的代码:
public Integer getParaSpacingBefore(XWPFParagraph paragraph, XWPFDocument docx) throws Exception {
if (paragraph.getSpacingBefore() != -1) {
return paragraph.getSpacingBefore();
}
if (docx.getStyles().getStyle(paragraph.getStyleID()) != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr() != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing() != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing().getBefore() != null) {
return docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing().getBefore().intValue();
}
}
}
}
// 文档默认段前行距
Integer spacingBefore = this.getDocxDefaultSpacing(docx, ThesisConstant.SPACING_BEFORE);
return spacingBefore;
}
3、获取段后行距的代码(分为段后行数和段后磅数):
① 获取段后行数的代码:
public Integer getParaSpacingAfterLines(XWPFParagraph paragraph, XWPFDocument docx) throws Exception {
if (paragraph.getSpacingAfterLines() != -1) {
return paragraph.getSpacingAfterLines();
}
if (docx.getStyles().getStyle(paragraph.getStyleID()) != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr() != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing() != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing().getAfterLines() != null) {
return docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing().getAfterLines().intValue();
}
}
}
}
// 文档默认段后行距
Integer afterLines = this.getDocxDefaultSpacing(docx, ThesisConstant.SPACING_AFTER_LINE);
return afterLines;
}
② 获取段后磅数的代码:
public Integer getParaSpacingAfter(XWPFParagraph paragraph, XWPFDocument docx) throws Exception {
if (paragraph.getSpacingAfter() != -1) {
return paragraph.getSpacingAfter();
}
if (docx.getStyles().getStyle(paragraph.getStyleID()) != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr() != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing() != null) {
if (docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing().getAfter() != null) {
return docx.getStyles().getStyle(paragraph.getStyleID()).getCTStyle().getPPr().getSpacing().getAfter().intValue();
}
}
}
}
// 文档默认段后行距
Integer spacingAfter = this.getDocxDefaultSpacing(docx, ThesisConstant.SPACING_AFTER);
return spacingAfter;
}
以上代码获取文档默认段前、后行距的代码如下:
// 获取文档默认段前、后行距
public Integer getDocxDefaultSpacing(XWPFDocument docx, String category) throws Exception {
if (docx.getStyle().getDocDefaults().getPPrDefault().getPPr() != null) {
if (docx.getStyle().getDocDefaults().getPPrDefault().getPPr().getSpacing() != null) {
CTSpacing spacing = docx.getStyle().getDocDefaults().getPPrDefault().getPPr().getSpacing();
if (category.equals(ThesisConstant.SPACING_BEFORE) ){
if (spacing.getBefore() != null) {
return spacing.getBefore().intValue();
}
} else if (category.equals(ThesisConstant.SPACING_BEFORE_Line)) {
if (spacing.getBeforeLines() != null) {
return spacing.getBeforeLines().intValue();
}
} else if (category.equals(ThesisConstant.SPACING_AFTER)) {
if (spacing.getAfter() != null) {
return spacing.getAfter().intValue();
}
} else if (category.equals(ThesisConstant.SPACING_AFTER_LINE)) {
if (spacing.getAfterLines() != null) {
return spacing.getAfterLines().intValue();
}
}
}
}
return 0;
}
4、获取段间行距的代码与上述类似,在此就不一一详述。
答:我的方法是:错误范围+错误具体位置+错误原因+如何改正。例如第一章的1.1章节标题“1.1 项目背景”中的“背景”二字的字体大小出现错误,则在检测报告中会生成这样一条信息:1.1标题中 ‘背景’,【中文字体大小错误】,应改为 小四。通过这样的一个规则,可以让用户快速定位错误并改正。