亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java解析pdf格式發(fā)票的代碼實現(xiàn)

 更新時間:2024年08月11日 09:10:48   作者:懶人wsh  
為了減少用戶工作量及誤操作的可能性,需要實現(xiàn)用戶上傳PDF格式的發(fā)票,系統(tǒng)通過解析PDF文件獲取發(fā)票內(nèi)容,并直接將其寫入表單,以下文章記錄了功能實現(xiàn)的代碼,需要的朋友可以參考下

發(fā)票樣式

發(fā)票內(nèi)容解析

引用Maven

使用pdfbox

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.24</version> <!-- 請檢查最新版本 -->
</dependency>

獲取PDF內(nèi)容

設(shè)置 sortByPosition 為 true 可以按文本位置提取內(nèi)容,否則獲取到的內(nèi)容錯亂,無法獲取到真正需要的內(nèi)容

    @RequestMapping("uploadReceiptsTest")
    @ResponseBody
    public Map<String,String> uploadReceiptsTest() throws Exception{
        String filePath = "D:/apache-tomcat-8.5.98/webapps/tspspic/發(fā)票文件/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;
    }

文本內(nèi)容(部分內(nèi)容以*替代)

    public static void main(String[] args) {
        String invoiceInfo = "電子發(fā)票(普通發(fā)票) 發(fā)票號碼:******\n" +
                             "開票日期:******\n" +
                             "購 名稱:****** 銷 名稱:******\n" +
                             "買 售\n" +
                             "方 方\n" +
                             "信 統(tǒng)一社會信用代碼/納稅人識別號:****** 信 統(tǒng)一社會信用代碼/納稅人識別號:******\n" +
                             "息 息\n" +
                             "項目名稱 規(guī)格型號 單 位 數(shù) 量 單 價 金 額 稅率/征收率 稅 額\n" +
                             "******* 100ml:5g 袋 800 4.070796 3256.64 13% 423.36\n" +
                             "******\n" +
                             "合 計 ¥3256.64 ¥423.36\n" +
                             "價稅合計(大寫) 叁仟陸佰捌拾圓整 (小寫)¥3680.00\n" +
                             "批號:******/ 生產(chǎn)日期:2024-05-15/ 有效期至:2026-04-30/ 含稅單價:4.6000/ 生產(chǎn)廠家:******/ 批準(zhǔn)文號:******/\n" +
                             "備 注\n" +
                             "開票人:王寧\n" +
                             "王寧";

解析文件內(nèi)容,返回數(shù)據(jù)

初版測試

    public Map<String,String> pdfStr(String invoiceInfo) {
 		//因解析出的括號不確定為中文還是英文,統(tǒng)一替換為英文字符
        invoiceInfo = invoiceInfo.replaceAll("(","(").replaceAll(")",")");
        // 定義正則表達(dá)式模式
        Pattern patternInvoiceNumber = Pattern.compile("發(fā)票號碼:(\\d+)");
        Pattern patternInvoiceDate = Pattern.compile("開票日期:(\\d{4}年\\d{1,2}月\\d{1,2}日)");
        Pattern patternBuyerName = Pattern.compile("購 名稱:(.+?) 銷 名稱:(.+?)\n");
        //由上圖可以發(fā)現(xiàn)“項目名稱 規(guī)格型號 單 位 數(shù) 量 單 價 金 額 稅率/征收率 稅 額”所需要的內(nèi)容在下一行數(shù)據(jù),使用笨方法直接獲取“稅額與合計”之間的數(shù)據(jù)通過之后的空格分割進(jìn)行獲取數(shù)據(jù)
        Pattern patternItemDetails = Pattern.compile("稅 額\\s+(.*?)合 計", Pattern.DOTALL);
        Pattern patternTotal = Pattern.compile("\\(小寫\\)¥(\\d+(\\.\\d+)?)");
        Pattern patternBatchNumber = Pattern.compile("批號:(.+?)/");
        Pattern patternProductionDate = Pattern.compile("生產(chǎn)日期:(\\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("生產(chǎn)廠家:(.+?)/");
        Pattern patternApprovalNumber = Pattern.compile("批準(zhǔn)文號:(.+?)/");
        Pattern patternIssuer = Pattern.compile("開票人:(.+)");

        // 創(chuàng)建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);

        // 提取數(shù)據(jù)
        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);
        }

        // 處理項目名稱、規(guī)格型號、單位、數(shù)量、單價、金額、稅率/征收率、稅額
        if (matcherItemDetails.find()) {
            String itemDetailsLine = matcherItemDetails.group(1).trim();
            itemDetailsLine = itemDetailsLine.replace("\n"," ");
            String[] details = itemDetailsLine.split(" "); // 按空格分割

            if (details.length >= 8) { // 確保有足夠的字段
            //因部分名稱過長,換行數(shù)據(jù)解析到最后進(jìn)行拼接
                productName = details[0].trim(); // 項目名稱
                if (details.length >= 9){
                    productName = details[0].trim()+details[8].trim(); // 項目名稱
                }
                specification = details[1].trim(); // 規(guī)格型號
                unit = details[2].trim(); // 單位
                quantity = Integer.parseInt(details[3].trim()); // 數(shù)量
                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("規(guī)格型號: " + specification);
                System.out.println("單位: " + unit);
                System.out.println("數(shù)量: " + 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);
        }

        // 輸出其他結(jié)果
        System.out.println("發(fā)票號碼: " + invoiceNumber);
        System.out.println("開票日期: " + invoiceDate);
        System.out.println("購買方名稱: " + buyerName);
        System.out.println("銷售方名稱: " + sellerName);
        System.out.println("價稅合計: " + total);
        System.out.println("批號: " + batchNumber);
        System.out.println("生產(chǎn)日期: " + productionDate);
        System.out.println("有效期至: " + expirationDate);
        System.out.println("含稅單價: " + taxIncludedPrice);
        System.out.println("生產(chǎn)廠家: " + manufacturer);
        System.out.println("批準(zhǔn)文號: " + approvalNumber);
        System.out.println("開票人: " + issuer);
    }

優(yōu)化代碼

  • Map存儲正則表達(dá)式:將所有正則表達(dá)式模式和對應(yīng)的字段名稱存儲在一個Map中,遍歷Map并執(zhí)行匹配,從而避免了為每個字段都寫單獨的匹配代碼。

  • 抽取通用邏輯:將匹配邏輯抽象成一個通用方法,簡化了代碼結(jié)構(gòu),減少了重復(fù)代碼。

  • 處理商品詳情:在匹配完itemDetails后,再拆分字符串并填充對應(yīng)的字段。

    public static Map<String, String> pdfStr(String invoiceInfo) {
        invoiceInfo = invoiceInfo.replaceAll("(", "(").replaceAll(")", ")");

        // 定義正則表達(dá)式模式
        Map<String, String> patterns = new HashMap<>();
        patterns.put("invoiceNumber", "發(fā)票號碼:(\\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", "生產(chǎn)日期:(\\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", "生產(chǎn)廠家:(.+?)/");
        patterns.put("approvalNumber", "批準(zhǔn)文號:(.+?)/");
        patterns.put("issuer", "開票人:(.+)");

        // 提取數(shù)據(jù)
        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());
            }
        }

        // 處理項目名稱、規(guī)格型號、單位、數(shù)量、單價、金額、稅率/征收率、稅額
        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());
            }
        }

        // 打印結(jié)果
        for (Map.Entry<String, String> entry : result.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }

        return result;
    }

到此這篇關(guān)于Java解析pdf格式發(fā)票的代碼實現(xiàn)的文章就介紹到這了,更多相關(guān)Java解析pdf格式發(fā)票內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot整合RabbitMQ示例詳解

    SpringBoot整合RabbitMQ示例詳解

    這篇文章主要介紹了SpringBoot整合RabbitMQ示例詳解,RabbitMQ是一個實現(xiàn)了AMQP高級消息隊列協(xié)議的消息隊列服務(wù),用Erlang語言。是面向消息的中間件,需要的朋友可以參考下
    2023-07-07
  • Spring中統(tǒng)一異常處理示例詳解

    Spring中統(tǒng)一異常處理示例詳解

    這篇文章主要給大家介紹了關(guān)于Spring中統(tǒng)一異常處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用spring具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • 詳解如何用spring Restdocs創(chuàng)建API文檔

    詳解如何用spring Restdocs創(chuàng)建API文檔

    這篇文章將帶你了解如何用spring官方推薦的restdoc去生成api文檔。具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • JAVA 生成隨機(jī)數(shù)并根據(jù)后臺概率靈活生成的實例代碼

    JAVA 生成隨機(jī)數(shù)并根據(jù)后臺概率靈活生成的實例代碼

    本篇文章主要介紹了JAVA 生成隨機(jī)數(shù)并根據(jù)后臺概率靈活生成的實例代碼,具有一定的參考價值,有興趣的可以了解一下
    2017-08-08
  • SpringBoot整合Kaptcha實現(xiàn)圖形驗證碼功能

    SpringBoot整合Kaptcha實現(xiàn)圖形驗證碼功能

    這篇文章主要介紹了SpringBoot整合Kaptcha實現(xiàn)圖形驗證碼功能,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • java springmvc 注冊中央調(diào)度器代碼解析

    java springmvc 注冊中央調(diào)度器代碼解析

    這篇文章主要介紹了java springmvc 注冊中央調(diào)度器代碼解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-08-08
  • Java使用路徑通配符加載Resource與profiles配置使用詳解

    Java使用路徑通配符加載Resource與profiles配置使用詳解

    這篇文章主要介紹了Java使用路徑通配符加載Resource與profiles配置使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Java實現(xiàn)圖章或簽名插在pdf的固定位置

    Java實現(xiàn)圖章或簽名插在pdf的固定位置

    使用Java技術(shù)在word轉(zhuǎn)換成pdf過程中實現(xiàn)將圖章或者簽名插入在pdf中,并生成帶圖章或者簽名的pdf,來完成某些特定場景的需求,文中有詳細(xì)的代碼示例,需要的朋友可以參考下
    2023-10-10
  • Spring Boot MyBatis 連接數(shù)據(jù)庫配置示例

    Spring Boot MyBatis 連接數(shù)據(jù)庫配置示例

    本篇文章主要介紹了Spring Boot MyBatis 連接數(shù)據(jù)庫示例的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • 詳解Java如何實現(xiàn)基于Redis的分布式鎖

    詳解Java如何實現(xiàn)基于Redis的分布式鎖

    在不同進(jìn)程需要互斥地訪問共享資源時,分布式鎖是一種非常有用的技術(shù)手段。這篇文章運用圖文和實例代碼介紹了Java如何實現(xiàn)基于Redis的分布式鎖,文章介紹的很詳細(xì),對Java和Redis剛興趣的朋友們可以參考借鑒,下面來一起看看。
    2016-08-08

最新評論