Java识别Word文档内容记录

前言

Word 文档内容识别主要由两部分:docdocx

docx 文档内容识别的难点在于:

  1. 格式不规范。
  2. 内容出现的规律

下面记录解析段落格式及内容。

一、docx内容提取

1、提取全文

提取全文内容相对简单

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
public class FileParsingService {
/**
* 解析 docx 的存文本内容
*
* @param file 文件
* @return 存文本内容
*/
public String parsingWordContent(Resource file) {
InputStream is = null;
try {
is = file.getInputStream();
XWPFDocument document = new XWPFDocument(is);
/*word 纯文本内容*/
return new XWPFWordExtractor(document).getText();
} catch (Exception e) {
log.warn("解析 word 失败,fileName={}", file.getFilename(), e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
log.warn("请关注输出入关闭失败", e);
}
}
}
return null;
}
}

2、提取有格式的内容

2.1、 基本原理

提取有格式的内容是按照段的方式提取的。

2.2、 获取所有段落

1
2
3
4
5
6
7
8
9
public class FileParsingService {
/*******************************/
public List<String> parsingWordOpinion(Resource file) throws Exception{
InputStream is = file.getInputStream();
XWPFDocument document = new XWPFDocument(is);
/*段落集合*/
List<IBodyElement> bodyElements = document.getBodyElements();
}
}

2.3、 处理段落

常用的几种段类型:

  • XWPFSDT 目录
  • XWPFParagraph 段落
  • XWPFTable 表格

2.3.1、XWPFSDT 目录

对于目录,直接获取目录内容就可以了

1
((XWPFSDT) bodyElement).getContent().getText()

2.3.2、XWPFParagraph 段落(重点)

作为段落的内容,又可以分为:

  • 标题
  • 序列(有序列、无序列)
  • 正文
2.3.2.1、提取段落正文
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
public class FileParsingUtil {
private final static boolean concatenatePhoneticRuns = true;
/**
* 输出超文本链接=false
*/
private final static boolean fetchHyperlinks = false;

/**
* 只提取段落内容
*
* @param document 文档
* @param paragraph 段落 (XWPFParagraph) bodyElement;
* @return 内容
*/

public static String extractParagraphText(XWPFDocument document, XWPFParagraph paragraph) {
StringBuilder text = new StringBuilder();
for (IRunElement run : paragraph.getIRuns()) {
if (run instanceof XWPFSDT) {
text.append(((XWPFSDT) run).getContent().getText());
} else if (!concatenatePhoneticRuns && run instanceof XWPFRun) {
text.append(((XWPFRun) run).text());
} else {
text.append(run);
}
/*提取超链接的链接*/
if (run instanceof XWPFHyperlinkRun && fetchHyperlinks) {
XWPFHyperlink link = ((XWPFHyperlinkRun) run).getHyperlink(document);
if (link != null)
text.append(" <").append(link.getURL()).append(">");
}
}
return text.toString();
}
}
2.3.2.2、提取段落的格式
1
2
XWPFParagraph paragraphTemp = (XWPFParagraph) bodyElement;
paragraphTemp.getStyleID()

格式有很多,比如:

  • 标题
    • Heading 1
    • Heading 2
    • RegHChG
    • RegH1G
    • RegH2G
  • 序列的合适
    • ListParagraph
    • RegSingleTxtG
    • RegSingleTxtG2

备注:但是需要的判断方式不是序列的格式,因为格式是不固定的。

格式内容在 wps样式和格式中都能看到。

2.3.2.3、判断是否为序列
1
2
3
4
XWPFParagraph paragraphTemp = (XWPFParagraph) bodyElement;
if(paragraphTemp.getNumID()!=null){
// 当前为序列
}

需要有两个重要属性

  • NumLevelText 序列值的格式化方式
    • %1、,根据序列的类型,可以为 1、一、a、
    • (%1),根据序列的类型,可以为 (1)(一)(a)
    • 暂未发现 %1%2 的区别——TODO
  • NumFmt 序列的类型
    • chineseCounting 中文
    • decimal 数字
    • decimalEnclosedCircleChinese 圆圈中的数字
    • upperLetter 大写字母
    • lowerLetter 小写字母
    • lowerRoman 小写罗马
    • upperRoman 大写罗马
    • bullet 无序(不用识别出方的、圆的和菱形的,没有意义)
    • 其它

2.3.3、XWPFTable 表格

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
public class FileParsingUtil {
/**
* 解析表格内容
*
* @param table 表格 (XWPFTable) bodyElement
* @return 表格内容
*/
public static String appendTableText(XWPFTable table) {
StringBuilder text = new StringBuilder();
//this works recursively to pull embedded tables from tables
for (XWPFTableRow row : table.getRows()) {
List<ICell> cells = row.getTableICells();
for (int i = 0; i < cells.size(); i++) {
ICell cell = cells.get(i);
if (cell instanceof XWPFTableCell) {
text.append(((XWPFTableCell) cell).getTextRecursively());
} else if (cell instanceof XWPFSDTCell) {
text.append(((XWPFSDTCell) cell).getContent().getText());
}
if (i < cells.size() - 1) {
text.append("\t");
}
}
text.append('\n');
}
return text.toString();
}
}

一段话:

在识别出内容出现的规律后,对于规范的格式,需要识别的内容也是多种多样的,需要打开 worddocx推荐用wps打开),然后打开样式和格式,对每个段落内容进行分析。

本文地址: https://github.com/maxzhao-it/blog/post/cb38f68c/