Java解析pdf格式发票的代码实现
发票样式
发票内容解析
引用Maven
使用pdfbox
<dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.24</version> <!-- 请检查最新版本 --> </dependency>
获取PDF内容
设置 sortByPosition 为 true 可以按文本位置提取内容,否则获取到的内容错乱,无法获取到真正需要的内容
@RequestMapping("uploadReceiptsTest") @ResponseBody public Map<String,String> uploadReceiptsTest() throws Exception{ String filePath = "D:/apache-tomcat-8.5.98/webapps/tspspic/发票文件/24372000000145100092.pdf"; // 保存路径 PDDocument document = PDDocument.load(new File(filePath)); PDFTextStripper pdfStripper = new PDFTextStripper(); // 排序文本行按其位置 pdfStripper.setSortByPosition(true); String text = pdfStripper.getText(document); document.close(); Map<String, String> map = pdfStr(text); return map; }
文本内容(部分内容以*替代)
public static void main(String[] args) { String invoiceInfo = "电子发票(普通发票) 发票号码:******\n" + "开票日期:******\n" + "购 名称:****** 销 名称:******\n" + "买 售\n" + "方 方\n" + "信 统一社会信用代码/纳税人识别号:****** 信 统一社会信用代码/纳税人识别号:******\n" + "息 息\n" + "项目名称 规格型号 单 位 数 量 单 价 金 额 税率/征收率 税 额\n" + "******* 100ml:5g 袋 800 4.070796 3256.64 13% 423.36\n" + "******\n" + "合 计 ¥3256.64 ¥423.36\n" + "价税合计(大写) 叁仟陆佰捌拾圆整 (小写)¥3680.00\n" + "批号:******/ 生产日期:2024-05-15/ 有效期至:2026-04-30/ 含税单价:4.6000/ 生产厂家:******/ 批准文号:******/\n" + "备 注\n" + "开票人:王宁\n" + "王宁";
解析文件内容,返回数据
初版测试
public Map<String,String> pdfStr(String invoiceInfo) { //因解析出的括号不确定为中文还是英文,统一替换为英文字符 invoiceInfo = invoiceInfo.replaceAll("(","(").replaceAll(")",")"); // 定义正则表达式模式 Pattern patternInvoiceNumber = Pattern.compile("发票号码:(\\d+)"); Pattern patternInvoiceDate = Pattern.compile("开票日期:(\\d{4}年\\d{1,2}月\\d{1,2}日)"); Pattern patternBuyerName = Pattern.compile("购 名称:(.+?) 销 名称:(.+?)\n"); //由上图可以发现“项目名称 规格型号 单 位 数 量 单 价 金 额 税率/征收率 税 额”所需要的内容在下一行数据,使用笨方法直接获取“税额与合计”之间的数据通过之后的空格分割进行获取数据 Pattern patternItemDetails = Pattern.compile("税 额\\s+(.*?)合 计", Pattern.DOTALL); Pattern patternTotal = Pattern.compile("\\(小写\\)¥(\\d+(\\.\\d+)?)"); Pattern patternBatchNumber = Pattern.compile("批号:(.+?)/"); Pattern patternProductionDate = Pattern.compile("生产日期:(\\d{4}-\\d{1,2}-\\d{1,2})/"); Pattern patternExpirationDate = Pattern.compile("有效期至:(\\d{4}-\\d{1,2}-\\d{1,2})/"); Pattern patternTaxIncludedPrice = Pattern.compile("含税单价:(\\d+(\\.\\d+)?)"); Pattern patternManufacturer = Pattern.compile("生产厂家:(.+?)/"); Pattern patternApprovalNumber = Pattern.compile("批准文号:(.+?)/"); Pattern patternIssuer = Pattern.compile("开票人:(.+)"); // 创建Matcher对象 Matcher matcherInvoiceNumber = patternInvoiceNumber.matcher(invoiceInfo); Matcher matcherInvoiceDate = patternInvoiceDate.matcher(invoiceInfo); Matcher matcherBuyerName = patternBuyerName.matcher(invoiceInfo); Matcher matcherItemDetails = patternItemDetails.matcher(invoiceInfo); Matcher matcherTotal = patternTotal.matcher(invoiceInfo); Matcher matcherBatchNumber = patternBatchNumber.matcher(invoiceInfo); Matcher matcherProductionDate = patternProductionDate.matcher(invoiceInfo); Matcher matcherExpirationDate = patternExpirationDate.matcher(invoiceInfo); Matcher matcherTaxIncludedPrice = patternTaxIncludedPrice.matcher(invoiceInfo); Matcher matcherManufacturer = patternManufacturer.matcher(invoiceInfo); Matcher matcherApprovalNumber = patternApprovalNumber.matcher(invoiceInfo); Matcher matcherIssuer = patternIssuer.matcher(invoiceInfo); // 提取数据 String invoiceNumber = ""; String invoiceDate = ""; String buyerName = ""; String sellerName = ""; String productName = ""; String specification = ""; String unit = ""; int quantity = 0; double unitPrice = 0.0; double amount = 0.0; String taxRate = ""; double taxAmount = 0.0; double total = 0.0; String batchNumber = ""; String productionDate = ""; String expirationDate = ""; double taxIncludedPrice = 0.0; String manufacturer = ""; String approvalNumber = ""; String issuer = ""; if (matcherInvoiceNumber.find()) { invoiceNumber = matcherInvoiceNumber.group(1); } if (matcherInvoiceDate.find()) { invoiceDate = matcherInvoiceDate.group(1); } if (matcherBuyerName.find()) { buyerName = matcherBuyerName.group(1); sellerName = matcherBuyerName.group(2); } // 处理项目名称、规格型号、单位、数量、单价、金额、税率/征收率、税额 if (matcherItemDetails.find()) { String itemDetailsLine = matcherItemDetails.group(1).trim(); itemDetailsLine = itemDetailsLine.replace("\n"," "); String[] details = itemDetailsLine.split(" "); // 按空格分割 if (details.length >= 8) { // 确保有足够的字段 //因部分名称过长,换行数据解析到最后进行拼接 productName = details[0].trim(); // 项目名称 if (details.length >= 9){ productName = details[0].trim()+details[8].trim(); // 项目名称 } specification = details[1].trim(); // 规格型号 unit = details[2].trim(); // 单位 quantity = Integer.parseInt(details[3].trim()); // 数量 unitPrice = Double.parseDouble(details[4].trim()); // 单价 amount = Double.parseDouble(details[5].trim()); // 金额 taxRate = details[6].trim(); // 税率/征收率 taxAmount = Double.parseDouble(details[7].trim()); // 税额 System.out.println("项目名称: " + productName); System.out.println("规格型号: " + specification); System.out.println("单位: " + unit); System.out.println("数量: " + quantity); System.out.println("单价: " + unitPrice); System.out.println("金额: " + amount); System.out.println("税率/征收率: " + taxRate); System.out.println("税额: " + taxAmount); } } if (matcherTotal.find()) { total = Double.parseDouble(matcherTotal.group(1)); } if (matcherBatchNumber.find()) { batchNumber = matcherBatchNumber.group(1); } if (matcherProductionDate.find()) { productionDate = matcherProductionDate.group(1); } if (matcherExpirationDate.find()) { expirationDate = matcherExpirationDate.group(1); } if (matcherTaxIncludedPrice.find()) { taxIncludedPrice = Double.parseDouble(matcherTaxIncludedPrice.group(1)); } if (matcherManufacturer.find()) { manufacturer = matcherManufacturer.group(1); } if (matcherApprovalNumber.find()) { approvalNumber = matcherApprovalNumber.group(1); } if (matcherIssuer.find()) { issuer = matcherIssuer.group(1); } // 输出其他结果 System.out.println("发票号码: " + invoiceNumber); System.out.println("开票日期: " + invoiceDate); System.out.println("购买方名称: " + buyerName); System.out.println("销售方名称: " + sellerName); System.out.println("价税合计: " + total); System.out.println("批号: " + batchNumber); System.out.println("生产日期: " + productionDate); System.out.println("有效期至: " + expirationDate); System.out.println("含税单价: " + taxIncludedPrice); System.out.println("生产厂家: " + manufacturer); System.out.println("批准文号: " + approvalNumber); System.out.println("开票人: " + issuer); }
优化代码
Map存储正则表达式:将所有正则表达式模式和对应的字段名称存储在一个Map中,遍历Map并执行匹配,从而避免了为每个字段都写单独的匹配代码。
抽取通用逻辑:将匹配逻辑抽象成一个通用方法,简化了代码结构,减少了重复代码。
处理商品详情:在匹配完itemDetails后,再拆分字符串并填充对应的字段。
public static Map<String, String> pdfStr(String invoiceInfo) { invoiceInfo = invoiceInfo.replaceAll("(", "(").replaceAll(")", ")"); // 定义正则表达式模式 Map<String, String> patterns = new HashMap<>(); patterns.put("invoiceNumber", "发票号码:(\\d+)"); patterns.put("invoiceDate", "开票日期:(\\d{4}年\\d{1,2}月\\d{1,2}日)"); patterns.put("buyerName", "购 名称:(.+?) 销 名称:(.+?)\n"); patterns.put("itemDetails", "税 额\\s+(.*?)合 计"); patterns.put("total", "\\(小写\\)¥(\\d+(\\.\\d+)?)"); patterns.put("batchNumber", "批号:(.+?)/"); patterns.put("productionDate", "生产日期:(\\d{4}-\\d{1,2}-\\d{1,2})/"); patterns.put("expirationDate", "有效期至:(\\d{4}-\\d{1,2}-\\d{1,2})/"); patterns.put("taxIncludedPrice", "含税单价:(\\d+(\\.\\d+)?)"); patterns.put("manufacturer", "生产厂家:(.+?)/"); patterns.put("approvalNumber", "批准文号:(.+?)/"); patterns.put("issuer", "开票人:(.+)"); // 提取数据 Map<String, String> result = new HashMap<>(); for (Map.Entry<String, String> entry : patterns.entrySet()) { Pattern pattern = Pattern.compile(entry.getValue(), Pattern.DOTALL); Matcher matcher = pattern.matcher(invoiceInfo); if (matcher.find()) { result.put(entry.getKey(), matcher.group(1).trim()); } } // 处理项目名称、规格型号、单位、数量、单价、金额、税率/征收率、税额 if (result.containsKey("itemDetails")) { String[] details = result.get("itemDetails").replace("\n", " ").split(" "); if (details.length >= 8) { result.put("productName", details[0].trim() + (details.length > 8 ? details[8].trim() : "")); result.put("specification", details[1].trim()); result.put("unit", details[2].trim()); result.put("quantity", details[3].trim()); result.put("unitPrice", details[4].trim()); result.put("amount", details[5].trim()); result.put("taxRate", details[6].trim()); result.put("taxAmount", details[7].trim()); } } // 打印结果 for (Map.Entry<String, String> entry : result.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } return result; }
到此这篇关于Java解析pdf格式发票的代码实现的文章就介绍到这了,更多相关Java解析pdf格式发票内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
java使用BeanUtils.copyProperties踩坑经历
最近在做个项目,踩了个坑特此记录一下,本文主要介绍了使用BeanUtils.copyProperties踩坑经历,需要的朋友们下面随着小编来一起学习学习吧2021-05-05SpringBoot中的WebSocketSession原理详解
这篇文章主要介绍了SpringBoot中的WebSocketSession原理详解,传统的 HTTP 协议是无法支持实时通信的,因为它是一种无状态协议,每次请求都是独立的,无法保持连接。为了解决这个问题,WebSocket 协议被引入,需要的朋友可以参考下2023-07-07spring boot之SpringApplication 事件监听
这篇文章主要介绍了spring boot之SpringApplication 事件监听,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2019-03-03
最新评论