利用Java實現(xiàn)Word文檔自動編號提取的方法詳解
一、背景
因業(yè)務需求,目前正在實現(xiàn)一項需求,即將一份試卷的內(nèi)容提取出來,由非結(jié)構(gòu)化到結(jié)構(gòu)化的轉(zhuǎn)換。在試卷解析的時候發(fā)現(xiàn)存在大綱目錄中帶有自動編號的格式,按照傳統(tǒng)的方式?jīng)]有解析出來,花了一番功夫,最終還是搞定了,于是寫下來分享給大家。
二、概述
從一份word格式的試卷中,用java從XWPFParagraph中先判斷是否有編號,如果有再提取自動編號,自動編號還是會區(qū)分不同類型的,如中文的一、二、三等,阿拉伯數(shù)字的1、2、3等,或者是字母a、b、c等。
三、正文
1、需要先實現(xiàn)一個自動編號上下文的class:
NumberingContext里面注冊了不同格式的編號,如大寫字母編號、小寫字母編號、中文編號等,具體可以看代碼:
public class NumberingContext {
private final Map<String, List<Integer>> numberingStates = new HashMap<>();
// 編號格式映射(可以擴展更多格式)
public static final Map<String, NumberFormatter> FORMATTERS = new HashMap<>();
static {
FORMATTERS.put("decimal", new DecimalFormatter());
FORMATTERS.put("lowerLetter", new LowerLetterFormatter());
FORMATTERS.put("upperLetter", new UpperLetterFormatter()); // 新增
FORMATTERS.put("upperRoman", new UpperRomanFormatter());
FORMATTERS.put("chineseCounting", new ChineseCountingFormatter());
}
public String resolveNumberText(String numIdKey, int ilvl, String format, String textTemplate) {
List<Integer> counters = numberingStates.computeIfAbsent(numIdKey, k -> new ArrayList<>());
// 確保層級計數(shù)器足夠長
while (counters.size() <= ilvl) {
counters.add(0);
}
// 更新當前層級計數(shù)器,并清空下級
counters.set(ilvl, counters.get(ilvl) + 1);
for (int i = ilvl + 1; i < counters.size(); i++) {
counters.set(i, 0);
}
// 獲取格式化器
NumberFormatter formatter = FORMATTERS.get(format);
if (formatter == null) {
formatter = new DecimalFormatter();
}
// 替換模板中的占位符
String result = textTemplate;
for (int i = 0; i <= ilvl; i++) {
String placeholder = "%" + (i + 1);
if (i < counters.size()) {
String replacement = formatter.format(counters.get(i));
result = result.replace(placeholder, replacement);
}
}
return result;
}
}2、不同類型的編號格式
1、DecimalFormatter
public class DecimalFormatter implements NumberFormatter {
@Override
public String format(int number) {
return String.valueOf(number);
}
}2、LowerLetterFormatter
public class LowerLetterFormatter implements NumberFormatter {
@Override
public String format(int number) {
return String.valueOf((char) ('a' + number - 1));
}
}3、UpperLetterFormatter
public class UpperLetterFormatter implements NumberFormatter {
@Override
public String format(int number) {
if (number < 1 || number > 26) {
throw new IllegalArgumentException("upperLetter 格式僅支持 1-26");
}
return String.valueOf((char) ('A' + number - 1));
}
}3、接下來就是核心邏輯:
這個getParagraphNumbering方法就是可以從XWPFParagraph
提取自動的編號
public static String getParagraphNumbering(NumberingContext numberingContext, XWPFParagraph paragraph) {
try {
if (paragraph.getNumID() == null) {
//"無編號";
return "";
}
BigInteger numId = paragraph.getNumID();
BigInteger ilvl = paragraph.getNumIlvl() != null ? paragraph.getNumIlvl() : new BigInteger("0");
// 使用numId和文檔信息創(chuàng)建唯一鍵
String numIdKey = numId.toString();
XWPFNumbering numbering = paragraph.getDocument().getNumbering();
if (numbering == null) {
//"無編號定義";
return "";
}
XWPFNum num = numbering.getNum(numId);
if (num == null) {
//"編號定義不存在";
return "";
}
BigInteger abstractNumId = num.getCTNum().getAbstractNumId().getVal();
for (XWPFAbstractNum abstractNum : numbering.getAbstractNums()) {
if (abstractNum.getCTAbstractNum().getAbstractNumId().equals(abstractNumId)) {
CTAbstractNum ctAbstractNum = abstractNum.getCTAbstractNum();
CTLvl ctLvl = ctAbstractNum.getLvlArray(ilvl.intValue());
if (ctLvl != null && ctLvl.getNumFmt() != null && ctLvl.getLvlText() != null) {
String format = ctLvl.getNumFmt().getVal().toString();
String text = ctLvl.getLvlText().getVal();
return numberingContext.resolveNumberText(
numIdKey, ilvl.intValue(), format, text);
}
}
}
//"編號層級不存在或定義不完整";
return "";
} catch (Exception e) {
//"解析編號時出錯";
return "";
}
}到此這篇關(guān)于利用Java實現(xiàn)Word文檔自動編號提取的方法詳解的文章就介紹到這了,更多相關(guān)Java Word文檔自動編號提取內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Maven項目中 Invalid bound statement 無效的綁定問題
這篇文章主要介紹了解決Maven項目中 Invalid bound statement 無效的綁定問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
java中List對象列表實現(xiàn)去重或取出及排序的方法
這篇文章主要介紹了關(guān)于java中List對象列表實現(xiàn)去重或取出以及排序的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面跟著小編來一起學習學習吧。2017-08-08
MybatisPlus:使用SQL保留字(關(guān)鍵字)的操作
這篇文章主要介紹了MybatisPlus:使用SQL保留字(關(guān)鍵字)的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
JAVA Netty實現(xiàn)聊天室+私聊功能的示例代碼
這篇文章主要介紹了JAVA Netty實現(xiàn)聊天室+私聊功能的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-08-08
MYSQL批量插入數(shù)據(jù)的實現(xiàn)代碼
非常的實現(xiàn)原理,代碼較多,建議大家仔細看看。2008-10-10
SpringBoot 項目添加 MDC 日志鏈路追蹤的執(zhí)行流程
日志鏈路追蹤就是將一個標志跨線程進行傳遞,在一般的小項目中也就是在你新起一個線程的時候,或者使用線程池執(zhí)行任務的時候會用到,比如追蹤一個用戶請求的完整執(zhí)行流程,本文給大家介紹SpringBoot MDC 日志鏈路追蹤的代碼,感興趣的朋友一起看看吧2021-06-06

