Java 实现将Word 转换成markdown

日常的开发中,需要将word 等各类文章信息转换成格式化语言,因此需要使用各类语言将word 转换成Markdown

1、引入 jar包

  <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency>

2、使用以下代码进行编写

package com.nd.ai.test.service.utils;import com.alibaba.fastjson.JSONObject;
import com.nd.ai.test.service.dto.apitest.FileMarkdownDTO;
import org.apache.commons.compress.utils.Lists;
import org.apache.poi.xwpf.usermodel.*;import java.io.*;
import java.util.List;
import java.util.UUID;/*** @ClassName WordToMarkdownConverter* @Author Administrator*/
public class WordToMarkdownConverter {public static FileMarkdownDTO convertWordToMarkdown(String wordPath) throws IOException {List<String> imagePathList = Lists.newArrayList();FileMarkdownDTO dto = new FileMarkdownDTO();try  {File file = new File(wordPath);String uuid = UUID.randomUUID().toString();String outputFilePath = file.getParent() + File.separator + uuid + ".md";File outputFile = new File(outputFilePath);FileInputStream fis = new FileInputStream(file); // Corrected to read the input fileXWPFDocument document = new XWPFDocument(fis);FileWriter writer = new FileWriter(outputFile);dto.setMdPath(outputFilePath);String imageDir = file.getParent() + File.separator + uuid + "-images";new File(imageDir).mkdirs(); // Create image directoryfor (IBodyElement element : document.getBodyElements()) {if (element instanceof XWPFParagraph) {processParagraph((XWPFParagraph) element, writer, imageDir, imagePathList);} else if (element instanceof XWPFTable) {processTable((XWPFTable) element, writer, imageDir, imagePathList);}}writer.close();// 增加读取mardkown 文件内容// Read the content of the generated Markdown fileStringBuilder markdownContent = new StringBuilder();try (BufferedReader br = new BufferedReader(new FileReader(outputFile))) {String line;while ((line = br.readLine()) != null) {markdownContent.append(line).append("\n");}}dto.setMarkdownContent(markdownContent.toString());dto.setParserStatus("success");} catch (IOException e){dto.setParserStatus("error");throw new IOException(e);}dto.setFileImagePathList(imagePathList);return dto;}private static void processParagraph(XWPFParagraph paragraph, FileWriter writer, String imageDir,List<String> imageNamePath) throws IOException {String content = processParagraphContent(paragraph, imageDir,imageNamePath);if (content.isEmpty()) return;// 处理标题和列表样式String style = paragraph.getStyle();if (style != null && style.startsWith("Heading")) {int level = Math.min(Character.getNumericValue(style.charAt(7)), 6);StringBuilder heading = new StringBuilder();for (int i = 0; i < level; i++) {heading.append("#");}heading.append(" ").append(content).append("\n\n");writer.write(heading.toString());
//            writer.write("#".repeat(level) + " " + content + "\n\n");} else if (isListParagraph(paragraph)) {String listMark = getListMark(paragraph);writer.write("* " + listMark + " " + content + "\n");} else {writer.write(content + "\n\n");}}private static String getListMark(XWPFParagraph para) {int indentLevel = para.getNumIlvl() != null ? para.getNumIlvl().intValue() : 0;String numFmt = para.getNumFmt(); // 获取列表编号格式// 处理有序列表if ("decimal".equals(numFmt) || "upperRoman".equals(numFmt)) {StringBuilder prefixBuilder = new StringBuilder();for (int i = 0; i < indentLevel * 4; i++) {prefixBuilder.append(" ");}String prefix = prefixBuilder.toString();return prefix + ".";}// 处理无序列表else {String bullet;switch (para.getNumFmt()) {case "bullet":bullet = "•"; // 实心圆点break;default:bullet = "-"; // 默认用减号break;}StringBuilder prefixBuilder = new StringBuilder();for (int i = 0; i < indentLevel * 4; i++) {prefixBuilder.append(" ");}return prefixBuilder.toString() + bullet;}}private static boolean isListParagraph(XWPFParagraph paragraph) {return isOrderedList(paragraph) || isUnorderedList(paragraph); // 如果没有找到对应的样式,则不可能是列表段落}private static boolean isOrderedList(XWPFParagraph paragraph) {if (paragraph.getNumFmt() != null) {String numFmt = paragraph.getNumFmt();return "decimal".equals(numFmt) || "upperRoman".equals(numFmt) || "lowerRoman".equals(numFmt) ||"upperLetter".equals(numFmt) || "lowerLetter".equals(numFmt);}return false;}private static boolean isUnorderedList(XWPFParagraph paragraph) {if (paragraph.getNumFmt() != null) {String numFmt = paragraph.getNumFmt();return "bullet".equals(numFmt);}return false;}private static void processTable(XWPFTable table, FileWriter writer, String imageDir,List<String> imageNamePath) throws IOException {StringBuilder mdTable = new StringBuilder();List<XWPFTableRow> rows = table.getRows();for (int i = 0; i < rows.size(); i++) {XWPFTableRow row = rows.get(i);mdTable.append("|");// 处理每个单元格for (XWPFTableCell cell : row.getTableCells()) {StringBuilder cellContent = new StringBuilder();// 处理单元格内的段落for (XWPFParagraph para : cell.getParagraphs()) {cellContent.append(processParagraphContent(para, imageDir,imageNamePath).replace("\n", "<br>"));}mdTable.append(cellContent.toString().trim()).append("|");}mdTable.append("\n");// 添加表头分隔线if (i == 0) {mdTable.append("|");for (int j = 0; j < row.getTableCells().size(); j++) {mdTable.append(" --- |");}mdTable.append("\n");}}writer.write(mdTable + "\n\n");}private static String processParagraphContent(XWPFParagraph paragraph, String imageDir,List<String> imageNamePath) throws IOException {StringBuilder sb = new StringBuilder();for (XWPFRun run : paragraph.getRuns()) {// 处理图片for (XWPFPicture picture : run.getEmbeddedPictures()) {sb.append(saveImage(picture, imageDir,imageNamePath)).append(" ");}// 处理文本样式String text = run.getText(0);if (text == null) continue;text = applyTextStyles(run, text);sb.append(text);}String content = sb.toString().trim();// 处理有序列表和无序列表if (isListParagraph(paragraph)) {String listMark = getListMark(paragraph);content ="* " + listMark + " " + content;}return content;}private static String applyTextStyles(XWPFRun run, String text) {if (run.isBold()) text = "**" + text + "**";if (run.isItalic()) text = "*" + text + "*";if (run.getUnderline() != UnderlinePatterns.NONE) text = "__" + text + "__";return text;}private static String saveImage(XWPFPicture picture, String imageDir,List<String> imageNamePath) throws IOException {XWPFPictureData picData = picture.getPictureData();String fileName = "img_" + UUID.randomUUID() + "." + picData.suggestFileExtension();File output = new File(imageDir, fileName);imageNamePath.add(output.getPath());try (FileOutputStream fos = new FileOutputStream(output)) {fos.write(picData.getData());}return "![" + fileName + "](" + imageDir + "/" + fileName + ")";}public static void main(String[] args) throws Exception {System.out.println(JSONObject.toJSONString( convertWordToMarkdown("word path")));}
}

获得信息

{
"fileImagePathList":["文件中图片路径1","文件中图片路径2"],
"markdownContent": "markdwon 信息",
"mdPath": "markdown文件地址"
}

运行上方的程序将会得到
1、解析文件中所有图片信息,保存到下方的地址
2、将word 文档转换成markdown
3、获取markdown 文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/42754.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iPhone mini,永远再见了

世界属于多数派&#xff0c;尽管有极少数人对 iPhone mini 情有独钟&#xff0c;但因为销量惨淡&#xff0c;iPhone mini 还是逃不开停产的命运。 据 Counterpoint 的数据&#xff0c;iPhone 12/13 mini 两代机型&#xff0c;仅占同期 iPhone 销量的 5%。 因为是小屏手机&…

监控易一体化运维:监控易机房管理,打造高效智能机房

在数字化浪潮中&#xff0c;企业对数据中心和机房的依赖程度与日俱增&#xff0c;机房的稳定运行成为业务持续开展的关键支撑。信息化的变迁&#xff0c;见证了机房管理从传统模式向智能化、精细化转变的过程。今天&#xff0c;就为大家深度剖析监控易在机房管理方面的卓越表现…

概率与决策理论

1.Q-learning Q-Learning 是一种无模型&#xff08;model-free&#xff09;强化学习算法&#xff0c;用于学习在马尔可夫决策过程&#xff08;MDP&#xff09;中的最优策略。它通过迭代更新 ​Q 值&#xff08;动作价值函数&#xff09;​ 来估计在某个状态下采取某个动作的长…

Python 学习路线推荐

文章目录 一、基础语法学习1.学习资源2.学习建议 二、数据处理与分析方向1. 数据处理库学习学习资源实践示例 2. 数据可视化实践示例 三、Web 开发方向1. Web 框架选择与学习学习资源实践示例 2. 前端知识补充学习资源 四、人工智能与机器学习方向1. 机器学习基础学习资源实践示…

如何让DeepSeek-R1在内网稳定运行并实现随时随地远程在线调用

前言&#xff1a;最近&#xff0c;国产AI圈里的新星——Deepseek&#xff0c;简直是火到不行。但是&#xff0c;你是不是已经对那些千篇一律的手机APP和网页版体验感到腻味了&#xff1f;别急&#xff0c;今天就带你解锁一个超炫的操作&#xff1a;在你的Windows电脑上本地部署…

SpringCloud+Mybatis-Plus+Docker+RabbitMQ+Redis+Elasticsearch黑马商城

一.MyBatis—Plus 一.快速入门 MybatisPlus介绍&#xff1a;MybatisPlus是一个基于Mybatis的增强工具库&#xff0c;旨在简化开发、提升效率&#xff0c;同时保留Mybatis的灵活性。它在Mybatis的基础上只做增强不做改变&#xff0c;引入它不会对现有工程产生影响 官网&#…

01 相机标定与相机模型介绍

学完本文,您将了解不同相机模型分类、内参意义,及对应的应用代码模型 标定的意义 建模三维世界点投影到二维图像平面的过程。标定输出的是相机模型。 相机模型 相机模型可以解理解为投影模型 +

如何在 Postman 中正确设置 Session 以维持用户状态?

在 Postman 里面设置有 session 的请求。如果你还不知道什么是 session&#xff0c;那么请看这里—— session 是一种记录客户端和服务器之间状态的机制&#xff0c;用于保持用户的登录状态或者其他数据&#xff0c;从而让用户在不同页面之间保持一致的体验。 Postman 设置带 …

免费使用!OpenAI 全量开放 GPT-4o 图像生成能力!

2025年3月26日&#xff0c;OpenAI正式推出GPT-4o原生图像生成功能&#xff0c;这一更新不仅标志着多模态AI技术的重大突破&#xff0c;更引发了全球AI厂商的激烈竞争。从免费用户到企业开发者&#xff0c;从创意设计到科学可视化&#xff0c;GPT-4o正在重塑图像生成的边界。本文…

【JavaScript】八、对象

文章目录 1、对象的声明2、对象的使用3、对象中的方法4、遍历对象5、内置对象Math 1、对象的声明 一种数据类型&#xff0c;使用typeof查看类型&#xff0c;结果是object可以详细的描述描述某个事物 声明语法&#xff1a; // 多用花括号形式声明 // 比如声明一个person对象 …

C++指针(五)完结篇

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 前言 相关文章&#xff1a;C指针&#xff08;一&#xff09;、C指针&#xff08;二&#xff09;、C指针&#xff08;三&#xff09;、C指针&#xff08;四&#xff09;万字图文详解&#xff01; 本篇博客是介…

DataGear 企业版 1.4.0 发布,数据可视化分析平台

DataGear 企业版 1.4.0 已发布&#xff0c;欢迎体验&#xff01; http://datagear.tech/pro/ 企业版 1.4.0 看板可视编辑模式新增了插入看板表单/面板布局、编辑图表联动、复制/粘贴、撤销/恢复等功能&#xff0c;具体更新内容如下&#xff1a; 新增&#xff1a;看板可视编辑…

windows第十八章 菜单、工具栏、状态栏

文章目录 创建框架窗口菜单菜单的风格通过资源创建菜单菜单的各种使用通过代码创建菜单在鼠标位置右键弹出菜单 CMenu常用函数介绍工具栏方式一&#xff0c;从资源创建工具栏方式二&#xff0c;代码创建 状态栏状态栏基础创建状态栏 创建框架窗口 手动创建一个空项目&#xff…

局域网共享失败?打印机/文件夹共享工具

很多时候&#xff0c;在办公或家庭环境中&#xff0c;我们需要进行打印机和文件夹的共享&#xff0c;以便更高效地协作和处理文件。然而&#xff0c;寻找对应版本的共享设置或是不想花费太多时间去进行复杂的电脑设置&#xff0c;总是让人感到头疼。今天&#xff0c;我要向大家…

C++中使用CopyFromRecordset将记录集拷贝到excel中时,如果记录集为0个,函数崩溃,是什么原因

文章目录 原因分析解决方案1. 检查记录集是否为空2. 安全调用COM方法3.进行异常捕获4. 替代方案&#xff1a;手动处理空数据 总结 在C中使用CopyFromRecordset将空记录集&#xff08;0条记录&#xff09;复制到Excel时崩溃的原因及解决方法如下&#xff1a; 原因分析 空记录集…

torchvision中数据集的使用

1、torchvision及其数据集的介绍 1.1 torchvision介绍 torchvision 是 PyTorch 的一个官方库&#xff0c;专门用于计算机视觉任务。它提供了以下核心功能&#xff1a; 预训练模型&#xff1a;如 ResNet、VGG、EfficientNet 等。数据集&#xff1a;内置常用视觉数据集&#xf…

d2025328

一、sql-判断三角形 610. 判断三角形 - 力扣&#xff08;LeetCode&#xff09; 用一下if加上判断条件 select x,y,z,if(xy > z and xz > y and yz > x and x-y < z and x-z < y and y-z < x,Yes,No) as triangle from Triangle 二、按照分类统计薪水 190…

C++20新特性:std::assume_aligned详解

文章目录 一、概述二、函数定义与语法三、使用方法与注意事项1. 使用方法2. 注意事项 四、性能优化原理五、实际应用场景六、编译器支持情况七、总结 一、概述 C20引入了std::assume_aligned&#xff0c;这是一个非常实用的特性&#xff0c;用于告知编译器某个指针所指向的对象…

洛谷P1706 全排列题解

P1706 全排列问题 题目描述 按照字典序输出自然数 1 1 1 到 n n n 所有不重复的排列&#xff0c;即 n n n 的全排列&#xff0c;要求所产生的任一数字序列中不允许出现重复的数字。 输入格式 一个整数 n n n。 输出格式 由 1 ∼ n 1 \sim n 1∼n 组成的所有不重复的…

yum install 报错(CentOS换源):

yum instally yum utils device mapper persistent-data lvm2 报错&#xff1a; 排查错误原因&#xff1a;centos7 系统停止维护了 解决方案&#xff1a;换源&#xff08;更换操作系统&#xff09; //1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-…