基于PDFBox的PDFTextStripper:如何提取指定关键词后的文本?
实现PDFBox精准提取触发词后的文本
当然可以做到!作为经常用PDFBox处理这类文本提取需求的开发者,我给你分享一个直接可行的方案——通过自定义PDFTextStripper子类来实现精准的文本过滤,完全符合你要的「仅提取QUANTITY之后文本、仅命中后行加入列表」的需求。
核心思路
PDFTextStripper本身是按文本块(通常对应视觉上的行)来处理PDF内容的,我们可以通过继承它,添加一个开关变量来控制何时开始收集文本:
- 初始化一个布尔标记
startExtracting,默认关闭 - 重写文本处理方法,每处理一段文本就检查是否包含触发词
QUANTITY - 一旦检测到触发词,打开开关;之后所有的文本块(行)都加入结果列表
具体代码实现
下面是完整的可运行示例代码,你可以直接调整后使用:
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.text.PDFTextStripper; import org.apache.pdfbox.text.TextPosition; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class QuantityFilteredStripper extends PDFTextStripper { // 触发开关,默认未激活 private boolean startExtracting = false; // 存储提取到的目标行 private final List<String> targetLines = new ArrayList<>(); // 定义要匹配的触发字符串 private static final String TRIGGER = "QUANTITY"; public QuantityFilteredStripper() throws IOException { super(); // 开启按视觉位置排序,避免PDF文本乱序 setSortByPosition(true); } @Override protected void writeString(String text, List<TextPosition> textPositions) throws IOException { // 检查当前行是否包含触发词 if (text.contains(TRIGGER)) { startExtracting = true; // 如果不需要包含QUANTITY所在行,直接return;需要的话就取消下面的注释 // targetLines.add(text.trim()); return; } // 开关激活后,收集当前行文本 if (startExtracting) { targetLines.add(text.trim()); } // 调用父类方法完成默认处理 super.writeString(text, textPositions); } // 获取最终提取的文本列表 public List<String> getTargetLines() { return targetLines; } // 测试入口 public static void main(String[] args) { try (PDDocument doc = PDDocument.load(new File("your-pdf-file.pdf"))) { QuantityFilteredStripper stripper = new QuantityFilteredStripper(); // 触发文本处理(这里不需要接收返回值,我们直接取targetLines) stripper.getText(doc); // 输出结果 for (String line : stripper.getTargetLines()) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }
注意事项
- 文本块与行的对应:大部分情况下
writeString处理的是视觉上的一行,但某些复杂PDF可能会把一行拆成多个文本块。如果遇到这种情况,可以考虑重写processTextPosition方法逐字符跟踪,或者先确保setSortByPosition(true)开启,保证文本顺序正确。 - 触发词跨块的情况:如果
QUANTITY被拆成了多个文本块(比如Q在一个块,UANTITY在另一个),需要额外做字符累计匹配,这种场景比较少见,但可以通过在子类中维护一个临时字符串来解决。 - 依赖版本:确保使用最新稳定版的PDFBox,避免兼容性问题。如果用Maven,依赖配置如下:
<dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.32</version> <!-- 替换为最新稳定版 --> </dependency>
内容的提问来源于stack exchange,提问作者Artjom Prozorov
相关产品推荐
相关产品推荐

