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

如何解决PDFBox提取PDF文本时的顺序混乱问题?

解决PDFBox提取文本顺序混乱的问题

问题根源

PDF文件中的文本并非按视觉阅读顺序存储,而是按照内容的绘制顺序(比如先绘制左侧列再绘制右侧列,或先绘制图片再绘制文本)存储。默认的PDFTextStripper会直接按这个绘制顺序输出文本,遇到多列、浮动元素等复杂布局时,就会出现提取顺序混乱的情况。

解决方案

1. 启用位置排序(常规布局首选)

PDFTextStripper内置了按坐标位置排序的功能,通过setSortByPosition(true)方法,可让文本优先从上到下(y坐标从高到低)、从左到右(x坐标从低到高)排列,这能解决大多数单页、单列PDF的提取问题。

修改后的代码:

PDDocument document = PDDocument.load(file);
PDFTextStripper textStripper = new PDFTextStripper();
textStripper.setSortByPosition(true); // 开启按位置排序
String[] auxTxt = textStripper.getText(document).split("\\r?\\n");

2. 自定义排序逻辑(复杂多列布局)

如果启用位置排序后仍有问题(比如多列PDF的文本被跨行拼接),可以继承PDFTextStripper,收集每个文本块的位置信息,实现完全自定义的排序逻辑。

示例自定义剥离器:

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ColumnAwareTextStripper extends PDFTextStripper {
    private final List<TextPosition> textPositionList = new ArrayList<>();

    public ColumnAwareTextStripper() throws IOException {
        super();
    }

    @Override
    protected void writeString(String text, List<TextPosition> textPositions) throws IOException {
        // 收集所有文本块的位置信息
        textPositionList.addAll(textPositions);
    }

    public String getSortedText() {
        // 先按y坐标降序(从上到下),再按x坐标升序(从左到右)排序
        Collections.sort(textPositionList, (tp1, tp2) -> {
            int yComparison = Double.compare(tp2.getY(), tp1.getY());
            if (yComparison != 0) {
                return yComparison;
            }
            return Double.compare(tp1.getX(), tp2.getX());
        });

        // 拼接排序后的文本
        StringBuilder result = new StringBuilder();
        for (TextPosition tp : textPositionList) {
            result.append(tp.getUnicode());
        }
        return result.toString();
    }
}

使用方式:

PDDocument document = PDDocument.load(file);
ColumnAwareTextStripper stripper = new ColumnAwareTextStripper();
stripper.getText(document); // 触发文本收集
String sortedText = stripper.getSortedText();
String[] auxTxt = sortedText.split("\\r?\\n");

3. 多列布局进阶优化

如果PDF是严格的多列布局,可进一步细化逻辑:

  • 按y坐标分组,将同一行的文本块归为一组
  • 对每组文本块按x坐标范围判断所属列
  • 按列顺序依次拼接每行的文本

这种方式需要根据PDF的实际列宽、间距调整坐标判断规则,确保列内文本顺序正确。

总结

  • 常规布局:直接使用setSortByPosition(true)即可快速解决顺序问题
  • 复杂布局:通过自定义PDFTextStripper子类,基于文本块的坐标位置实现排序逻辑,确保提取顺序符合视觉阅读顺序

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 02:42:31