如何解决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
相关产品推荐
相关产品推荐

