You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让PDFBox提取PDF表格时保留空白字段?

问题:提取PDF表格时保留空白列数据的解决方案

需求

读取PDF文档中的表格数据,必须保留空白列的位置信息,确保能区分空白对应的是买入数量还是卖出数量等列。

问题

使用PDFBox提取表格文本时,空白列会被直接跳过,导致输出的字段顺序混乱,无法判断空白对应的具体列。比如原本买入数量为空、卖出数量有值的行,输出时会把卖出数量前移,和买入数量有值的行无法区分。

当前尝试

  • 尝试设置pdfStripper.setSortByPosition(true),无效
  • 查找过相关问题案例,未找到有效解决方法

PDF中的表格结构

订单号时间买入数量卖出数量价格已结算
123456709:23:45250354.4
123458913:38:10300400
123467714:28:15100980
123472215:45:50265770

当前输出(空白列丢失)

"1234567 09:23:45 250 354.4"
"1234589 13:38:10 300 400"
"1234677 14:28:15 100 980"
"1234722 15:45:50 265 770"

期望输出(保留空白列位置)

"1234567 09:23:45 250   354.4  "
"1234589 13:38:10 300   400  "
"1234677 14:28:15    100 980  "
"1234722 15:45:50    265 770  "

现有代码

String pdfText = "";
try {
       File file =  new File("C:\\data.pdf");
       PDDocument pdDocument = Loader.loadPDF(file);
       // Tried the below option as well, but does not help
       pdfStripper.setSortByPosition(true);
       pdfText = pdfStripper.getText(pdDocument);
       pdDocument.close();
      } catch (IOException e) {
          e.printStackTrace();
      }
    
String[] arrayPDF = pdfText.split("\\r?\\n");
for (String data : arrayPDF) {
                System.out.println(data);
            }

解决方案建议

方法1:用PDFTextStripperByArea定位列边界

PDF表格的列有固定位置,先确定每一列的x坐标范围,逐行提取每个区域的文本,空白区域保留空字符串:

try (PDDocument doc = Loader.loadPDF(new File("C:\\data.pdf"))) {
    PDFTextStripperByArea stripper = new PDFTextStripperByArea();
    // 示例坐标,需用PDFDebugger工具查看实际列位置调整
    stripper.addRegion("orderId", new Rectangle2D.Double(10, 20, 80, 20));
    stripper.addRegion("time", new Rectangle2D.Double(100, 20, 80, 20));
    stripper.addRegion("buyQty", new Rectangle2D.Double(190, 20, 80, 20));
    stripper.addRegion("sellQty", new Rectangle2D.Double(280, 20, 80, 20));
    stripper.addRegion("price", new Rectangle2D.Double(370, 20, 80, 20));
    stripper.addRegion("settled", new Rectangle2D.Double(460, 20, 80, 20));

    PDPage page = doc.getPage(0); // 多页需循环处理
    stripper.extractRegions(page);

    // 提取各区域文本,空区域返回空字符串
    String orderId = stripper.getTextForRegion("orderId").trim();
    String time = stripper.getTextForRegion("time").trim();
    String buyQty = stripper.getTextForRegion("buyQty").trim();
    String sellQty = stripper.getTextForRegion("sellQty").trim();
    String price = stripper.getTextForRegion("price").trim();
    String settled = stripper.getTextForRegion("settled").trim();

    // 按固定格式拼接,保留空白位置
    String line = String.format("%-8s %-8s %-8s %-8s %-8s %-8s", 
        orderId, time, buyQty, sellQty, price, settled);
    System.out.println("\"" + line + "\"");
} catch (IOException e) {
    e.printStackTrace();
}

方法2:使用专门的PDF表格提取库

若PDF结构复杂,推荐用专业表格提取工具,比如Tabula-java:

try {
    File pdfFile = new File("C:\\data.pdf");
    PDDocument doc = Loader.loadPDF(pdfFile);
    PDPage page = doc.getPage(0);
    
    // Tabula表格提取逻辑
    SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
    List<Table> tables = sea.extract(page);

    for (Table table : tables) {
        List<List<Rectangle>> cells = table.getCells();
        for (List<Rectangle> row : cells) {
            StringBuilder sb = new StringBuilder();
            for (Rectangle cell : row) {
                String text = extractTextFromCell(page, cell).trim();
                sb.append(String.format("%-8s", text));
            }
            System.out.println("\"" + sb.toString() + "\"");
        }
    }
    doc.close();
} catch (IOException e) {
    e.printStackTrace();
}

// 辅助方法:提取指定单元格文本
private static String extractTextFromCell(PDPage page, Rectangle cell) throws IOException {
    PDFTextStripperByArea stripper = new PDFTextStripperByArea();
    stripper.addRegion("cell", new Rectangle2D.Double(cell.getX(), cell.getY(), cell.getWidth(), cell.getHeight()));
    stripper.extractRegions(page);
    return stripper.getTextForRegion("cell");
}

方法3:自定义文本位置映射

提取所有文本块的位置信息,按y坐标分组行、x坐标分组列,空白列填充空字符串:

try (PDDocument doc = Loader.loadPDF(new File("C:\\data.pdf"))) {
    PDFTextStripper stripper = new PDFTextStripper() {
        @Override
        protected void writeString(String text, List<TextPosition> textPositions) throws IOException {
            // 收集每个文本块的位置与内容
            for (TextPosition tp : textPositions) {
                System.out.println("X: " + tp.getX() + ", Y: " + tp.getY() + ", Text: " + tp.getUnicode());
            }
        }
    };
    stripper.getText(doc);
    // 后续按y坐标分组行,x坐标匹配列,空白列填充空字符串
} catch (IOException e) {
    e.printStackTrace();
}

内容的提问来源于stack exchange,提问作者iCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 19:47:40