门户网站建站方案,安卓app定制开发公司,深圳便宜网站建设,戴尔公司网站建设为了减少用户工作量及误操作的可能性#xff0c;需要实现用户上传PDF格式的发票#xff0c;系统通过解析PDF文件获取发票内容#xff0c;并直接将其写入表单。以下文章记录了功能实现的代码。
发票样式 发票内容解析
引用Maven
使用pdfbox
dependencygroupI…为了减少用户工作量及误操作的可能性需要实现用户上传PDF格式的发票系统通过解析PDF文件获取发票内容并直接将其写入表单。以下文章记录了功能实现的代码。
发票样式 发票内容解析
引用Maven
使用pdfbox
dependencygroupIdorg.apache.pdfbox/groupIdartifactIdpdfbox/artifactIdversion2.0.24/version !-- 请检查最新版本 --
/dependency
获取PDF内容
设置 sortByPosition 为 true 可以按文本位置提取内容否则获取到的内容错乱无法获取到真正需要的内容 RequestMapping(uploadReceiptsTest)ResponseBodypublic MapString,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();MapString, String map pdfStr(text);return map;}文本内容(部分内容以*替代)
public static void main(String[] args) {String invoiceInfo 电子发票普通发票 发票号码******\n 开票日期******\n 购 名称****** 销 名称******\n 买 售\n 方 方\n 信 统一社会信用代码/纳税人识别号****** 信 统一社会信用代码/纳税人识别号******\n 息 息\n 项目名称 规格型号 单 位 数 量 单 价 金 额 税率/征收率 税 额\n ******* 100ml5g 袋 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 MapString,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 MapString, String pdfStr(String invoiceInfo) {invoiceInfo invoiceInfo.replaceAll(, ().replaceAll(, ));// 定义正则表达式模式MapString, 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, 开票人(.));// 提取数据MapString, String result new HashMap();for (Map.EntryString, 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.EntryString, String entry : result.entrySet()) {System.out.println(entry.getKey() : entry.getValue());}return result;}