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

如何用iText API从PDF提取表格数据并加载到JTable?

如何从PDF中提取特定表格数据并加载到JTable?

你当前用iText提取了PDF整页的文本行,但要精准拿到表格内容,得针对表格的结构做针对性处理,这里有几个实用的方案:


1. 升级到iText 7使用专门的表格提取API

如果可以升级iText版本,iText 7提供了更易用的表格提取工具,能直接识别PDF中的表格结构,不用自己处理文本拆分。示例代码如下:

import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.canvas.parser.listener.TableExtractor;
import com.itextpdf.layout.element.Table;
import java.util.List;

public class PdfTableExtractor {
    public static void main(String[] args) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader("quotation.pdf"));
        // 提取第3页的所有表格
        TableExtractor extractor = new TableExtractor(pdfDoc);
        List<Table> tables = extractor.extractTable(3);
        
        for (Table table : tables) {
            int rowCount = table.getNumberOfRows();
            int colCount = table.getNumberOfColumns();
            // 遍历表格行和列,获取单元格内容
            for (int row = 0; row < rowCount; row++) {
                for (int col = 0; col < colCount; col++) {
                    String cellContent = table.getCell(row, col).getText();
                    System.out.print(cellContent + "\t");
                    // 这里可以直接把cellContent添加到JTable的DefaultTableModel中
                }
                System.out.println();
            }
        }
        pdfDoc.close();
    }
}

这个方法的优势是iText会自动处理表格的边框、单元格合并等复杂情况,提取结果更准确。


2. 用iText 5的底层解析器定位表格区域(如果不想升级版本)

如果你继续使用iText 5,可以通过自定义RenderListener来识别表格的坐标范围,只提取该区域内的文本。核心思路是:

  • 解析PDF页面的线条,找到表格的边界(上下左右坐标)
  • 重写renderText方法,判断文本的位置是否在表格区域内,只保留符合条件的文本

示例代码片段:

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
import com.itextpdf.text.Rectangle;

public class TableAreaExtractor implements RenderListener {
    private Rectangle tableBounds; // 表格的边界矩形,需要提前确定
    private StringBuilder tableText = new StringBuilder();

    public TableAreaExtractor(Rectangle tableBounds) {
        this.tableBounds = tableBounds;
    }

    @Override
    public void beginTextBlock() {}

    @Override
    public void renderText(TextRenderInfo renderInfo) {
        // 获取文本的位置矩形
        Rectangle textRect = renderInfo.getBaseline().getBoundingRectange();
        // 判断文本是否在表格区域内
        if (tableBounds.contains(textRect)) {
            tableText.append(renderInfo.getText()).append("\n");
        }
    }

    @Override
    public void endTextBlock() {}

    @Override
    public void renderImage(com.itextpdf.text.pdf.parser.ImageRenderInfo renderInfo) {}

    public String getTableText() {
        return tableText.toString();
    }
}

// 使用方式
PdfReader reader = new PdfReader("quotation.pdf");
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
// 假设表格的坐标是x=50, y=200, width=500, height=300,需要根据实际PDF调整
Rectangle tableBounds = new Rectangle(50, 200, 550, 500);
TableAreaExtractor listener = new TableAreaExtractor(tableBounds);
parser.processContent(3, listener);
String tableText = listener.getTableText();
// 拆分表格行和单元格
String[] tableLines = tableText.split("\r\n|\r|\n");
for (String line : tableLines) {
    String[] cells = line.split("\\s{2,}"); // 按多个空格拆分单元格
    // 将cells添加到JTable模型
}
reader.close();

注意:表格的坐标需要你通过PDF工具(比如Adobe Acrobat的测量工具)获取,或者通过解析页面的线条自动识别,后者需要额外处理线条解析的逻辑。


3. 基于文本格式特征过滤表格行

如果你的PDF表格格式非常规整(比如有固定的起始/结束标识、每行有固定数量的分隔符),可以在现有代码基础上添加过滤逻辑。比如:

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
import java.util.Arrays;

public class SimpleTableFilter {
    public static void main(String[] args) throws Exception {
        PdfReader reader = new PdfReader("quatation.pdf");
        String textFromPage = PdfTextExtractor.getTextFromPage(reader, 3);
        String[] lines = textFromPage.split("\r\n|\r|\n");

        // 假设表格从包含"Item No"的行开始,到包含"Total"的行结束
        boolean isInTable = false;
        for (String line : lines) {
            if (line.contains("Item No")) {
                isInTable = true;
            }
            if (isInTable) {
                // 拆分单元格,这里假设用多个空格作为分隔符
                String[] cells = line.split("\\s{2,}");
                // 添加到JTable模型
                System.out.println(Arrays.toString(cells));
            }
            if (line.contains("Total")) {
                isInTable = false;
            }
        }
        reader.close();
    }
}

这种方法简单快捷,但只适用于格式固定的表格,对复杂表格(比如单元格换行、合并)处理效果不好。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:18:28