java解析PDF、WORD获取中的表格以及文本内容

近期因工作需要需要解析PDF,需要把PDF中的文本和表格分离,最终要实现的目标是PDF中的文本内容放一块,表格内容放一块,以list的形式存储。解析PDF的技术有很多,经过多次尝试发现使用AdobeAcrobat可以实现表格和文本分离。

注意事项:

1、下载AdobeAcrobat进行安装
       链接:https://pan.baidu.com/s/1Ki2H4gxDaKj5z8Dli3amCg 
       提取码:ckfx

2、使用时如果有报jacob的错把jacob-1.18-M1-x64.dll、jacob-1.18-M1-x86.dll这两个文件放到Java>jdk1.8.0_271>bin目录下

3、引入依赖:

     <dependency><groupId>jacob</groupId><artifactId>jacob</artifactId><version>1.1.8</version></dependency> <dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.17.2</version></dependency>

工具类如下(内附PDF的文件转换方法以及获取纯文本和纯表格的测试方法):

package com.ylx.test.util;import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
/*** * 2024年4月18日下午3:53:36*/
@Component
public class PdfToHtmlAdobe {public static void main(String[] args) throws Exception {/*** 将PDF转成html* */String filepath = "E:\\工作\\";String htmlpath = "E:\\gong_hang\\zjk\\html_file\\";String filename = "cehi";Integer fileType = 1;//1.pdf,2wordString ext = ".pdf";filedata(filepath, filename,htmlpath,fileType,ext);/*** 获取纯文本* */String htmlFilePath = "E:\\gongzuo\\html_file\\ceshi.html";List<String> dlList = getDLList(htmlFilePath);for (int i = 0; i < dlList.size(); i++) {System.out.println("第"+i+"条:"+dlList.get(i));}/*** 获取所有表格* */List<String> bgList = getAllTable(htmlFilePath);for (int i = 0; i < bgList.size(); i++) {System.out.println("第"+i+"条:"+bgList .get(i));}}public static String getRemoveTableStr(String htmlFilePath) throws IOException {String content = new String(Files.readAllBytes(Paths.get(htmlFilePath)),"GBK");String specialStr = removeContentStyle(content);// 使用 Jsoup 解析 HTML 字符串Document doc = Jsoup.parse(specialStr);// 获取纯文本String plainText = doc.text();
//		System.out.println(plainText);return plainText;}/*** 获取所有的Table* @param htmlFilePath* @return* @throws IOException* 2024年4月19日下午3:36:39*/public static List<String> getAllTable(String htmlFilePath) throws IOException {List<String> bgList = new ArrayList<>();// 加载 HTML 文件File input = new File(htmlFilePath);try {// 解析 HTML 文件Document doc = Jsoup.parse(input, null);// 选择所有的表格元素Elements tables = doc.select("table");// 遍历每个表格元素for (Element table : tables) {// 获取当前表格中的所有行Elements rows = table.select("tr");//创建StringBuilder类的实例StringBuilder builder = new StringBuilder();// 遍历每行for (Element row : rows) {// 输出行内容
//                    System.out.println("行内容:");
//                    System.out.println(row.text());//将获取的text写入StringBuilder容器builder.append(row.text());builder.append("\r\n");}
//                System.out.println("-----------------------------------------------");
//                System.out.println(builder.toString());
//                System.out.println("-----------------------------------------------");bgList.add(builder.toString());}} catch (IOException e) {e.printStackTrace();}return bgList;}/*** 获取以10个逗号为一个段落的list* @param content* @return* 2024年4月19日下午2:04:17* @throws IOException */public static List<String> getDLList(String htmlFilePath) throws IOException {/*** 删除Table表格* */String content = getRemoveTableStr(htmlFilePath);
//		System.out.println(content);
//        String[] jhArr = content.split("。");
//        List<String> dlList = new ArrayList<String>();//10个句号为一个段落
//        String jhStrTen=new String();
//        int lastDl=0;
//        for (int i = 0; i < jhArr.length; i++) {
//        	if (i % 10 == 0 && i>0) {
//        		dlList.add(jhStrTen);
//        		if (jhArr.length-i>10) {
//        			jhStrTen="";
//				}
//        		if (jhArr.length-i<=10 && lastDl==0) {
//					lastDl = 1;
//					jhStrTen = "";
//				}
//			}else{
//				jhStrTen = jhStrTen +jhArr[i]+"。";
//				if ((i+1) == jhArr.length) {
//					dlList.add(jhStrTen);
//				}
//			}
//		}List<String> dlList = new ArrayList<>();int index = 0;while (index < content.length()) {int endIndex = index + 1; // 初始化结束索引for (int i = 0; i < 10; i++) {endIndex = content.indexOf("。", endIndex + 1); // 查找句号if (endIndex == -1) {break; // 如果没有找到句号,跳出循环}}if (endIndex == -1) {endIndex = content.length(); // 如果不满十个句号,结束索引为字符串长度}dlList.add(content.substring(index, endIndex)); // 将段落添加到列表中index = endIndex + 1; // 更新起始索引}return dlList;}/*** @param filepath  存放PDF的文件目录* @param filename  不带后缀名的PDF文件* @throws Exception* 2024年4月18日下午3:31:55*/public static void filedata(String fileDir, String filename,String htmlPath,Integer fileType,String ext) throws Exception{final ExecutorService exec = Executors.newFixedThreadPool(1);  Callable<String> call = new Callable<String>() {  public String call() throws Exception {  //开始执行耗时操作  if (fileType==1) {//文件路径不存在则进行创建FileUtils.createPath(htmlPath);if (!FileUtils.isFileExists(htmlPath + filename + ".docx")) {PDFtoWord(fileDir + filename + ".PDF", htmlPath + filename + ".docx");}if (!FileUtils.isFileExists(htmlPath + filename + ".html")) {wordToHtml(htmlPath + filename + ".docx", htmlPath + filename + ".html");}}if (fileType==2){//文件路径不存在则进行创建FileUtils.createPath(htmlPath);if (!FileUtils.isFileExists(htmlPath + filename + ".html")) {wordToHtml(fileDir + filename + ext, htmlPath + filename + ".html");}}return "线程执行完成.";}  };  try {Future<String> future = exec.submit(call);String obj = future.get(1000 * 600, TimeUnit.MILLISECONDS); //任务处理超时时间设为 1 秒  System.out.println("文件转换:" + obj);} catch (Exception e) {//关闭AcrobatString command = "taskkill /f /im Acrobat.exe";  Runtime.getRuntime().exec(command);throw e;} finally {// 关闭线程池  exec.shutdown(); }}public static boolean wordToHtml(String inPath, String toPath) {ComThread.InitSTA();//初始化com的线程// 启动wordActiveXComponent axc = new ActiveXComponent("Word.Application");boolean flag = false;try {// 设置word不可见axc.setProperty("Visible", new Variant(false));Dispatch docs = axc.getProperty("Documents").toDispatch();// 打开word文档Dispatch doc = Dispatch.invoke(docs,"Open",Dispatch.Method,new Object[] { inPath, new Variant(false), new Variant(true) },new int[1]).toDispatch();// 作为html格式保存到临时文件Dispatch.invoke(doc, "SaveAs", Dispatch.Method, new Object[] {toPath, new Variant(8) }, new int[1]);Variant f = new Variant(false);Dispatch.call(doc, "Close", f);axc.invoke("Quit", new Variant[] {});flag = true;return flag;} catch (Exception e) {e.printStackTrace();return flag;} finally {ComThread.Release();//关闭com的线程   真正kill进程}}public static boolean PDFtoWord(String source, String target) {ComThread.InitSTA();//初始化com的线程// pdfActiveX PDDoc对象 主要建立PDF对象ActiveXComponent app = null ;try {File inPath = new File(source);File outPath = new File(target);app = new ActiveXComponent("AcroExch.PDDoc");// PDF控制对象Dispatch pdfObject = app.getObject();long start = System.currentTimeMillis();// 打开PDF文件,建立PDF操作的开始Dispatch.call(pdfObject, "Open", new Variant(inPath.getAbsolutePath()));Variant jsObj = Dispatch.call(pdfObject, "GetJSObject");Dispatch.call(jsObj.getDispatch(), "SaveAs", outPath.getPath(), "com.adobe.acrobat.docx");app.invoke("Close");// 关闭PDFapp.invoke("Close", new Variant[] {});long end = System.currentTimeMillis();} catch (Exception e) {System.out.println(e.getMessage());} finally {ComThread.Release();//关闭com的线程   真正kill进程}return true;}public static String chineseDate(String chineseDate){String aa4 = chineseDate.substring(chineseDate.indexOf("年")-2, chineseDate.indexOf("年"));String aa1 = chineseDate.substring(chineseDate.indexOf("年"),chineseDate.indexOf("月")+1);String aa2 = chineseDate.substring(chineseDate.indexOf("月")+1,chineseDate.indexOf("日"));String aa3 = chineseDate.substring(chineseDate.indexOf("日"));aa1 = aa1.replaceAll("十二", "12");aa1 = aa1.replaceAll("十一", "11");aa1 = aa1.replaceAll("十", "10");aa1 = aa1.replaceAll("一", "1");aa1 = aa1.replaceAll("二", "2");aa1 = aa1.replaceAll("三", "3");aa1 = aa1.replaceAll("四", "4");aa1 = aa1.replaceAll("五", "5");aa1 = aa1.replaceAll("六", "6");aa1 = aa1.replaceAll("七", "7");aa1 = aa1.replaceAll("八", "8");aa1 = aa1.replaceAll("九", "9");aa1 = aa1.replaceAll("零", "0");aa1 = aa1.replaceAll("〇", "0");aa1 = aa1.replaceAll("○", "0");aa1 = aa1.replaceAll("O", "0");aa1 = aa1.replaceAll("", "0");aa4 = aa4.replaceAll("十二", "12");aa4 = aa4.replaceAll("十一", "11");aa4 = aa4.replaceAll("十", "10");aa4 = aa4.replaceAll("一", "1");aa4 = aa4.replaceAll("二", "2");aa4 = aa4.replaceAll("三", "3");aa4 = aa4.replaceAll("四", "4");aa4 = aa4.replaceAll("五", "5");aa4 = aa4.replaceAll("六", "6");aa4 = aa4.replaceAll("七", "7");aa4 = aa4.replaceAll("八", "8");aa4 = aa4.replaceAll("九", "9");aa4 = aa4.replaceAll("零", "0");aa4 = aa4.replaceAll("〇", "0");aa4 = aa4.replaceAll("○", "0");aa4 = aa4.replaceAll("O", "0");aa4 = aa4.replaceAll("", "0");return 20+aa4+aa1+chineseNumber(aa2)+aa3;}/*** 中文數字转阿拉伯数组【十万九千零六十  --> 109060】* @param chineseNumber* @return*/private static String chineseNumber(String chineseNumber){int result = 0;int temp = 1;//存放一个单位的数字如:十万int count = 0;//判断是否有chArrchar[] cnArr = new char[]{'一','二','三','四','五','六','七','八','九'};char[] chArr = new char[]{'十','百','千','万','亿'};for (int i = 0; i < chineseNumber.length(); i++) {boolean b = true;//判断是否是chArrchar c = chineseNumber.charAt(i);for (int j = 0; j < cnArr.length; j++) {//非单位,即数字if (c == cnArr[j]) {if(0 != count){//添加下一个单位之前,先把上一个单位值添加到结果中result += temp;temp = 1;count = 0;}// 下标+1,就是对应的值temp = j + 1;b = false;break;}}if(b){//单位{'十','百','千','万','亿'}for (int j = 0; j < chArr.length; j++) {if (c == chArr[j]) {switch (j) {case 0:temp *= 10;break;case 1:temp *= 100;break;case 2:temp *= 1000;break;case 3:temp *= 10000;break;case 4:temp *= 100000000;break;default:break;}count++;}}}if (i == chineseNumber.length() - 1) {//遍历到最后一个字符result += temp;}}return String.valueOf(result);}/***  读取本地html文件里的html代码* @return*/public static String toHtmlString(File file) {// 获取HTML文件流StringBuffer htmlSb = new StringBuffer();try {BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "GBK"));while (br.ready()) {htmlSb.append(br.readLine());}br.close();// 删除临时文件//file.delete();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}// HTML文件字符串String htmlStr = htmlSb.toString();// 返回经过清洁的html文本return htmlStr;}/*** 符合以特定字符串开头 ,以特定字符串结尾的所有结果*/public static String getSpecialStr(String line, String pattern) {// 创建 Pattern 对象Pattern r = Pattern.compile(pattern);// 创建 matcher 对象Matcher m = r.matcher(line);String str = "";if (m.find()) {str = m.group(2);}if (StringUtils.isEmpty(str)) {return str;} else {return str.substring(0, str.length() - 1);}}/*** 清除文件中的table** @param content*            公告内容* @return 字符串结果集*/public static String removeContentStyle(String content) {String regEx = "<table(.*?)</table>";Pattern p = Pattern.compile(regEx);Matcher m = p.matcher(content);if (m.find()) {content = m.replaceAll("");}
//            String regEx2 = " style=\"([\\s\\S]*?)\"";
//            Pattern p2 = Pattern.compile(regEx2);
//            Matcher m2 = p2.matcher(content);
//            if (m2.find()) {
//                    content = m2.replaceAll("");
//            }
//            String regEx3 = " border=\"(.*?)\"";
//            Pattern p3 = Pattern.compile(regEx3);
//            Matcher m3 = p3.matcher(content);
//            if (m3.find()) {
//                    content = m3.replaceAll(" border=\"1\" ");
//            }
//
//            String regEx4 = " class=.*?\\>";
//            Pattern p4 = Pattern.compile(regEx4);
//            Matcher m4 = p4.matcher(content);
//            if (m4.find()) {
//                    content = m4.replaceAll("\\>");
//            }
//            String regEx5 = "\\<!--(.*?)--\\>";
//            Pattern p5 = Pattern.compile(regEx5);
//            Matcher m5 = p5.matcher(content);
//            if (m5.find()) {
//                    content = m5.replaceAll("");
//            }
//            String regEx6 = "\\<o:p(.*?)/o:p\\>";
//            Pattern p6 = Pattern.compile(regEx6);
//            Matcher m6 = p6.matcher(content);
//            if (m6.find()) {
//                    content = m6.replaceAll("");
//            }
//            String regEx7 = "\\<!(.*?)\\>";
//            Pattern p7 = Pattern.compile(regEx7);
//            Matcher m7 = p7.matcher(content);
//            if (m7.find()) {
//                    content = m7.replaceAll("");
//            }
//            String regEx8 = "\\<font(.*?)\\>";
//            Pattern p8 = Pattern.compile(regEx8);
//            Matcher m8 = p8.matcher(content);
//            if (m8.find()) {
//                    content = m8.replaceAll("");
//            }return content;}}

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

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

相关文章

TensorFlow轻松入门(一)(更新中)

常见模块 tf. &#xff1a;包含了张量定义&#xff0c;变换等常用函数和类&#xff1b;tf.data&#xff1a;输入数据处理模块&#xff0c;提供了像tf.data.Dataset等类用于封装输入数据&#xff0c;指定批量大小等&#xff1b;tf.image&#xff1a;图像处理模块&#xff0c;提…

el-form 表单设置某个参数非必填验证

html <el-form ref"form" :rules"rules"><el-form-item prop"tiktokEmail" label"邮箱" ><el-input v-model"form.tiktokEmail" placeholder"邮箱" ></el-input></el-form-item&…

mybatis中foreach使用

一、foreach 属性使用 <foreach collection"list" index"index" item"mchntCd" open"(" close")" separator",">#{mchntCd} </foreach>item&#xff1a; 集合中元素迭代时的别名&#xff0c;该参数为…

项目实战:Qt获取CTP量化交易接口测试数据工具 v1.0.0(获取深度行情数据、订阅取消订阅)

若该文为原创文章&#xff0c;转载请注明出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/137937666 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

VSCODE自定义代码片段简述与基础使用

目录 一、 简述二 、 基础使用说明2.1 新建一个代码块工作区间2.2 语法 三、 示例四、 参考链接 一、 简述 VSCode的自定义代码片段功能允许开发者根据自己的需求定义和使用自己的代码片段&#xff0c;从而提高编码效率。 优点: 提高效率&#xff1a; 自定义代码片段能够减少…

springboot+Vue实现分页

文章目录 一、后端二、前端 今天开发的有一个场景就是需要从远程ssh服务器上加载一个文件展示到前端&#xff0c;但是一次性拉过来有几万条数据&#xff0c;一下载加载整个文件会导致前端非常非常的卡&#xff0c;于是要使用分页解决&#xff0c;我之前看过的有mybatis的分页查…

乐鑫的ESP32-S3芯片的LE能实现beacon功能吗?

最近帮一个客户做ESP32定位器方案&#xff0c;客户提出这个疑问&#xff0c;乐鑫的ESP32-S3芯片的LE能实现beacon功能吗&#xff1f;针对这个问题&#xff0c;启明云端工程师小启给出这样的回复。 回答是可以的&#xff0c;大家可以看idf的例程。 ESP-IDF iBeacon demo From …

时间,空间复杂度讲解——夯实根基

前言&#xff1a;本节内容属于数据结构的入门知识——算法的时间复杂度和空间复杂度。 时间复杂度和空间复杂度的知识点很少&#xff0c; 也很简单。 本节的主要篇幅会放在使用具体例题来分析时间复杂度和空间复杂度。本节内容适合刚刚接触数据结构或者基础有些薄弱的友友们哦。…

C/C++开发,opencv-ml库学习,随机森林(RTrees)应用

目录 一、随机森林算法 1.1 算法简介 1.2 OpenCV-随机森林&#xff08;Random Forest&#xff09; 二、cv::ml::RTrees应用 2.2 RTrees应用 2.2 程序编译 2.3 main.cpp全代码 一、随机森林算法 1.1 算法简介 随机森林算法是一种集成学习&#xff08;Ensemble Learning&a…

软件著作权合作开发协议撰写指南

由两个以上的自然人、法人或者非法人组织合作开发的软件,其著作权的归属由合作开发者签订书面合同约定。无书面合同或者合同未作明确约定,合作开发的软件可以分割使用的,开发者对各自开发的部分可以单独享有著作权;但是,行使著作权时,不得扩展到合作开发的软件整体的著作…

大语言模型在研究领域的应用——推荐系统中的大语言模型

推荐系统中的大语言模型 大语言模型作为推荐模型基于特定提示的方法基于指令微调的方法大语言模型增强的推荐模型数据输入增强语义表示增强偏好表示增强大语言模型作为推荐模拟器总结应用建议现存问题和未来方向推荐系统的核心在于捕捉并理解用户的潜在偏好,进而为用户推送合适…

Python 语音识别系列-实战学习之初识语音识别

Python 语音识别系列-实战学习之初识语音识别 前言1.语音识别简介2.语音识别的工作原理3.语音识别的基本模块4.语音识别的发展历史5.语音识别的应用场景6.语音识别的Python案例7.总结 前言 在本篇博客中&#xff0c;将介绍语音识别的基础知识&#xff0c;包括其定义、工作原理…

百度沈抖:智能,生成无限可能

4月16日&#xff0c;Create 2024百度AI开发者大会在深圳举行。会上&#xff0c;百度集团执行副总裁、百度智能云事业群总裁沈抖正式发布新一代智能计算操作系统——百度智能云万源。它能管理万卡规模的集群&#xff0c;极致地发挥GPU、CPU的性能&#xff1b;它有强大的大模型作…

本地环境运行Llama 3大型模型:可行性与实践指南

简介&#xff1a; Llama 是由 Meta&#xff08;前身为 Facebook&#xff09;的人工智能研究团队开发并开源的大型语言模型&#xff08;LLM&#xff09;&#xff0c;它对商业用途开放&#xff0c;对整个人工智能领域产生了深远的影响。继之前发布的、支持4096个上下文的Llama 2…

19. TypeScript 类型运算符

TypeScript作为JavaScript的超集&#xff0c;不仅提供了静态类型检查&#xff0c;还引入了多种类型运算符&#xff0c;使得类型定义更加灵活和强大。这些运算符可以帮助我们构建更加精确和灵活的类型定义。本文将详细介绍这些类型运算符的用法和应用场景。 keyof 运算符 keyo…

Python 数据可视化 boxplot

Python 数据可视化 boxplot import pandas as pd import matplotlib.pyplot as plt import numpy as np import seaborn as sns# 读取 TSV 文件 df pd.read_csv(result.tsv, sep\t)normal_df df[df["sample_name"].str.contains("normal")] tumor_df df…

重磅!!!监控分布式NVIDIA-GPU状态

简介&#xff1a;Uptime Kuma是一个易于使用的自托管监控工具&#xff0c;它的界面干净简洁&#xff0c;部署和使用都非常方便&#xff0c;用来监控GPU是否在占用&#xff0c;非常美观。 历史攻略&#xff1a; docker应用&#xff1a;搭建uptime-kuma监控站点 win下持续观察…

新能源汽车电池盒尺寸检测

SNK施努卡电池盒错漏装和尺寸检测 随着环境污染和能源短缺问题日益突出&#xff0c;新能源汽车作为一种环保、可持续的交通工具得到了广泛关注和推广。其中&#xff0c;电池是新能源汽车的核心部件之一&#xff0c;其性能和质量直接影响到整车的续航能力和安全性。而电池盒作为…

Unity Meta Quest MR 开发(七):使用 Stencil Test 模板测试制作可以在虚拟与现实之间穿梭的 MR 传送门

文章目录 &#x1f4d5;教程说明&#x1f4d5;Stencil Test 模板测试&#x1f4d5;Stencil Shader&#x1f4d5;使用 Unity URP 渲染管线设置模板测试⭐Render Pipeline Asset 与 Universal Renderer Data⭐删除场景中的天空盒⭐设置虚拟世界的层级 Layer⭐设置模板测试 &#…

《Vid2Seq》论文笔记

原文链接 [2302.14115] Vid2Seq: Large-Scale Pretraining of a Visual Language Model for Dense Video Captioning (arxiv.org) 原文笔记 What&#xff1a; 《Vid2Seq: Large-Scale Pretraining of a Visual Language Model for Dense Video Captioning》 作者提出一种多…