基于Java实现文档章节结构智能提取方案详解

 更新时间:2026年09月02日 11:57:48   作者:风萧萧1999  
本文主要介绍了一种基于Java的文档章节结构智能提取方案,采用多策略融合方法处理非结构化文档,方案包含三个核心模块,感兴趣的小伙伴可以了解下

在数字化文档处理场景中,自动提取文档的章节结构是一项核心需求,尤其是面对无书签的PDF、纯文本文档等非结构化数据时,如何精准识别标题层级、构建树形章节结构成为关键。

本文将分享一套基于Java实现的文档章节结构智能提取方案,涵盖大模型辅助识别、文本规则分析、Unstructured JSON解析三种核心场景。

一、整体设计思路

本方案的核心类为DetectTitleChapters,整体提取逻辑遵循“优先大模型识别,兜底规则分析”的策略,同时支持从Unstructured输出的JSON数据中解析章节结构。核心流程如下:

  1. 大模型优先识别:利用LLM对文本进行目录解析,输出标准化JSON格式的章节结构;
  2. 规则兜底分析:若大模型识别失败,通过文本规则匹配、层级判定提取标题;
  3. 层级结构整理:对识别出的标题进行排序,构建父子层级关系;
  4. Unstructured JSON解析:针对结构化输出的JSON,基于element_id和parent_id构建树形章节。

二、核心功能实现

2.1 依赖与基础配置

核心依赖包括FastJSON2(JSON解析)、Apache Commons Lang3(字符串处理)、Slf4j(日志)等。

2.2 大模型辅助章节提取

通过调用大模型API,传入定制化Prompt,让LLM解析文本并输出标准化的章节JSON结构,适合结构化程度低但文本规范的文档。

private List<Chapter> getLLMChapters(String input) {
    List<Chapter> allTitles = new ArrayList<>();
    if (input.length() > 100000) // 限制文本长度,避免大模型调用超限
        return allTitles;
    try {
        // 获取大模型配置(模型编码、API地址、密钥)
        KbLlmModelsCacheService.KbLlmModelDto model = kbLlmModelsCacheService.getChatModel().getModelMapById().get(2L);
        // 定制化Prompt,约束输出格式为JSON
        String prompt = "角色:你是一名文档解析助手,请对用户的输入文本进行解析,找到目录所在,输出文本的章节目录结构。\n" +
                "输出格式:JSON格式:[{\"title\":\"标题\", \"level\":2, \"pageNumber\":7, \"subChapters\":[]}\n" +
                "约束条件:输出原文";
        JSONObject cfgLLM = new JSONObject();
        cfgLLM.put("model", model.getModelCode());
        cfgLLM.put("prompt", prompt);
        cfgLLM.put("url", model.getApiUrl());
        cfgLLM.put("authorization", model.getApiKey());
        // 调用大模型API
        JSONObject result = httpUtils.chatMessages(input, cfgLLM);
        if (result.getBoolean("success")) {
            String    content   = result.getString("content");
            JSONArray jsonArray = httpUtils.formatListJSON(content);
            allTitles = Chapter.parseChapter(jsonArray); // 解析JSON为Chapter对象
        } else
            log.info("大模型识别目录失败:" + result.toJSONString());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return allTitles;
}

2.3 文本规则分析提取章节

当大模型识别失败时,通过文本规则匹配标题特征,判定层级并构建章节结构,核心分为“标题判定”“层级识别”“结构整理”三步。

2.3.1 标题判定规则

通过正则匹配、关键词过滤等方式,筛选出符合标题特征的文本行:

public static boolean isTitleText(String text) {
    // 过滤空文本、制表符、特殊标点
    if (text.trim().isEmpty() || text.matches("\t") || text.contains("\t") || text.contains("。") || text.endsWith("、"))
        return false;
    // 过滤纯数字/特殊符号文本
    String cleanText = text.trim();
    if (cleanText.matches("^[0-9\\p{Punct}]+$"))
        return false;
    // 过滤长度异常文本(2-50字符为合理标题长度)
    if (text.length() > 50 || text.length() < 2) return false;
    // 匹配常见标题格式(第X章、X.1、一、(一)等)
    for (Pattern pattern : TITLE_PATTERNS) {
        if (pattern.matcher(text).matches()) {
            return true;
        }
    }
    // 匹配标题关键词(概况、总则、前言等)
    String[] titleKeywords = {"概况", "概述", "前言", "引言", "摘要", "总结", "结论", "总则"};
    for (String keyword : titleKeywords) {
        if (text.contains(keyword)) {
            return true;
        }
    }
    return false;
}

// 常见标题格式正则
private static final List<Pattern> TITLE_PATTERNS = Arrays.asList(
        Pattern.compile("^第[零一二三四五六七八九十百千\\d]+章[\\s ]+(.+)$"),
        Pattern.compile("^第[零一二三四五六七八九十百千\\d]+节[\\s ]+(.+)$"),
        Pattern.compile("^\\d+[.\\.](?!.*%).*[^%]$"),
        Pattern.compile("^[一二三四五六七八九十]、[\\s ]*(.+)$"),
        Pattern.compile("^[\\((][一二三四五六七八九十][\\))][\\s\\t]*(.+)$"),
        Pattern.compile("^\\d+[.\\.]\\d+[.\\.].[^%]$")
);

2.3.2 章节层级识别

根据标题格式判定层级(1级:第X章/一、;2级:(一)/X.1;其他为非标题):

public static int detectChapterLevel(String text) {
    text = text.trim();
    // 1级标题:第X章、中文数字+顿号
    if (text.matches("^第[零一二三四五六七八九十百千\\d]+章.*") || text.matches("^[零一二三四五六七八九十百千\\d]+、.*")) {
        return 1;
    }
    // 2级标题:(一)、X.X格式
    if (text.matches("^[\\((][一二三四五六七八九十][\\))][\\s\\t]*(.+)$") || text.matches("^\\d+[.\\.]\\d+[.\\.].[^%]$")) {
        return 2;
    }
    return 0; // 非标题
}

2.3.3 层级结构整理

利用栈结构构建父子层级关系,核心逻辑是“弹出栈中层级≥当前层级的节点,将当前节点加入父节点子列表”:

public List<Chapter> organizeChaptersByLevel(List<Chapter> rawChapters) {
    List<Chapter>  rootChapters = new ArrayList<>();
    Stack<Chapter> levelStack   = new Stack<>(); // 栈记录当前层级父节点

    for (Chapter chapter : rawChapters) {
        int level = chapter.getLevel();
        // 找到当前节点的父节点(栈顶层级 < 当前层级)
        while (!levelStack.isEmpty() && levelStack.peek().getLevel() >= level) {
            levelStack.pop();
        }
        // 根节点(无父节点)加入根列表,否则加入父节点子列表
        if (levelStack.isEmpty()) {
            rootChapters.add(chapter);
        } else {
            levelStack.peek().getSubChapters().add(chapter);
        }
        // 当前节点入栈,作为后续子节点的父节点
        levelStack.push(chapter);
    }
    return rootChapters;
}

2.4 解析Unstructured JSON章节结构

针对Unstructured工具输出的JSON数据,基于element_idparent_id构建树形章节:

public List<Chapter> extractChaptersFromUnstructured(JSONArray responseJson) {
    List<Chapter> chapters = new ArrayList<>();
    Map<String, Chapter> chapterMap = new HashMap<>(); // element_id -> Chapter
    Map<String, List<Chapter>> parentChildrenMap = new HashMap<>(); // parent_id -> 子章节

    // 第一步:提取所有Title类型元素
    for (Object parsed : responseJson) {
        JSONObject parsedObject = (JSONObject) parsed;
        String     type         = parsedObject.getString("type");
        if (StringUtils.isNotEmpty(type) && type.toLowerCase().contains("title")) {
            String     elementId = parsedObject.getString("element_id");
            String     text      = parsedObject.getString("text");
            JSONObject metadata  = parsedObject.getJSONObject("metadata");
            Integer    depth     = metadata != null ? metadata.getInteger("category_depth") : null;
            String     parentId  = metadata != null ? metadata.getString("parent_id") : null;

            int level = (depth != null ? depth : 0) + 1; // 层级计算(depth从0开始)
            Chapter chapter = new Chapter(text, level, 0);
            chapterMap.put(elementId, chapter);

            // 建立父子映射
            if (parentId != null && !parentId.isEmpty()) {
                parentChildrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(chapter);
            } else {
                chapters.add(chapter); // 无父节点为根章节
            }
        }
    }

    // 第二步:将子章节挂载到父章节
    for (Map.Entry<String, List<Chapter>> entry : parentChildrenMap.entrySet()) {
        String        parentId = entry.getKey();
        List<Chapter> children = entry.getValue();
        Chapter       parent   = chapterMap.get(parentId);
        if (parent != null) {
            parent.getSubChapters().addAll(children);
        }
    }
    return chapters;
}

三、核心入口方法

对外提供统一的章节提取入口,自动选择提取策略:

public List<Chapter> extractChapters(String content) throws IOException {
    log.info("开始大模型识别文本标题");
    if (content == null || content.isEmpty())
        return new ArrayList<>();

    List<Chapter> llmChapters = getLLMChapters(content);
    if (llmChapters.isEmpty()) {
        log.info("未检测到大模型识别的文本标题,开始文本分析识别文本标题");
        return getChaptersByAnalysis(content);
    } else
        return llmChapters;
}

四、方案优势与扩展方向

4.1 优势

  1. 多策略兜底:大模型+规则双策略,兼顾识别精度和稳定性;
  2. 通用性强:支持纯文本、Unstructured JSON等多种输入格式;
  3. 层级精准:通过正则+栈结构,精准构建章节父子关系;
  4. 可配置化:标题正则、关键词、层级规则均可按需调整。

4.2 扩展方向

  1. 字体特征融合:若解析PDF时能获取字体大小、加粗等特征,可融入层级判定逻辑,提升精度;
  2. 自定义规则:支持配置化管理标题正则、关键词,适配不同行业文档(如法律、医疗、技术文档);
  3. 大模型优化:优化Prompt模板,加入更多格式约束,提升LLM输出稳定性;
  4. 性能优化:针对超长文本,实现分段处理、并行解析,提升处理效率。

五、总结

本文的文档章节提取方案,结合了大模型的智能解析能力和规则引擎的稳定性,能够高效处理各类非结构化文档的章节提取需求。

以上就是基于Java实现文档章节结构智能提取方案详解的详细内容,更多关于Java文档章节结构智能提取的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot中默认异常处理机制的实现

    SpringBoot中默认异常处理机制的实现

    本文主要介绍了Spring Boot 中的默认异常处理机制,如 /error 接口,用于统一返回错误信息,具有一定的参考价值,感兴趣的可以了解一下
    2025-08-08
  • SpringBoot项目构建的实现过程

    SpringBoot项目构建的实现过程

    SpringBoot简化了基于Spring框架的项目开发,提供自动配置、嵌入式容器等功能;可通过多种方式创建SpringBoot项目,如Maven、IDEA、STS等;Spring好项目后可可运行并测试,文中还详细介绍了SpringBoot的核心功能、创建项目的的步骤和一些配置方法
    2026-04-04
  • Mybatis动态SQL的实现示例

    Mybatis动态SQL的实现示例

    这篇文章主要介绍了Mybatis动态SQL的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • Spring Boot使用过滤器Filter过程解析

    Spring Boot使用过滤器Filter过程解析

    这篇文章主要介绍了Spring Boot使用过滤器Filter过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Spring Boot 2.4版本前后的分组配置变化及对多环境配置结构的影响(推荐)

    Spring Boot 2.4版本前后的分组配置变化及对多环境配置结构的影响(推荐)

    这篇文章主要介绍了Spring Boot 2.4版本前后的分组配置变化及对多环境配置结构的影响,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • 关于Springboot数据库配置文件明文密码加密解密的问题

    关于Springboot数据库配置文件明文密码加密解密的问题

    这篇文章主要介绍了Springboot数据库配置文件明文密码加密解密的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • 快速入门介绍Java中强大的String.format()

    快速入门介绍Java中强大的String.format()

    这篇文章主要给大家介绍了如何快速入门介绍Java中强大的String.format()的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-03-03
  • Java源码解析之详解ReentrantLock

    Java源码解析之详解ReentrantLock

    今天给大家带来的是关于Java并发的相关知识,文章围绕着ReentrantLock源码展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Java JDK Validation 注解解析与使用方法验证

    Java JDK Validation 注解解析与使用方法验证

    Jakarta Validation提供了一种声明式、标准化的方式来验证Java对象,与框架无关,可以方便地集成到各种Java应用中,本文给大家介绍Java JDK Validation 注解解析与使用,感兴趣的朋友一起看看吧
    2025-09-09
  • Java中的魔法类:sun.misc.Unsafe示例详解

    Java中的魔法类:sun.misc.Unsafe示例详解

    Java是一个安全的开发工具,它阻止开发人员犯很多低级的错误,而大部份的错误都是基于内存管理方面的。如果你想搞破坏,可以使用Unsafe这个类。下面这篇文章主要给大家介绍了关于Java中魔法类:sun.misc.Unsafe的相关资料,需要的朋友可以参考下
    2018-05-05

最新评论