当前位置: 代码网 > it编程>编程语言>Java > 基于Java实现文档章节结构智能提取方案详解

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

2026年09月02日 Java 我要评论
在数字化文档处理场景中,自动提取文档的章节结构是一项核心需求,尤其是面对无书签的pdf、纯文本文档等非结构化数据时,如何精准识别标题层级、构建树形章节结构成为关键。本文将分享一套基于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文档章节结构智能提取的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com