如何使用PDFBox解析含键值对结构的PDF文件?
嘿,你已经用PDFLayoutTextStripper搞定了格式良好的文本提取,这步走得很稳!接下来要解析那些someKey1 someValue1这类键值对,我给你几个实用的方案,你可以根据自己PDF的实际格式来选:
方案1:简单字符串分割(适合键值对格式固定的场景)
如果你的键值对是键和值用空格分隔,而且每行一个键值对,直接对提取到的文本做分割就够了。要是值里可能包含空格,记得用split(" ", 2)只拆分第一个空格,避免把值拆碎:
// 承接你已有的代码,拿到text之后 Map<String, String> keyValueMap = new HashMap<>(); String[] lines = text.split("\\n"); // 按行分割文本 for (String line : lines) { String[] keyValueParts = line.split(" ", 2); // 只拆分成键、值两部分 if (keyValueParts.length == 2) { String key = keyValueParts[0].trim(); String value = keyValueParts[1].trim(); // 可以加个过滤,只处理符合命名规则的键(比如以someKey开头) if (key.startsWith("someKey")) { keyValueMap.put(key, value); } } } // 打印解析结果 keyValueMap.forEach((k, v) -> System.out.println(k + ": " + v));
方案2:正则表达式匹配(应对更灵活的格式)
如果键值对可能夹杂在其他文本里,或者键的命名有更复杂的规律(比如someKey后面跟数字),正则表达式会更靠谱。下面这个正则能匹配someKey+数字格式的键,自动捕获后面的对应值,直到遇到下一个键或者文本结尾:
// 承接已有的text字符串 Map<String, String> keyValueMap = new HashMap<>(); Pattern keyValuePattern = Pattern.compile("(someKey\\d+)\\s+(.*?)(?=\\s+someKey|\\Z)"); Matcher matcher = keyValuePattern.matcher(text); while (matcher.find()) { String key = matcher.group(1).trim(); String value = matcher.group(2).trim(); keyValueMap.put(key, value); } // 输出结果 keyValueMap.forEach((k, v) -> System.out.println(k + ": " + v));
简单解释下这个正则:
(someKey\\d+):捕获以someKey开头、后面跟数字的键\\s+:匹配键和值之间的空格(.*?):非贪婪匹配值的内容,直到遇到下一个someKey或者文本结束
方案3:结合文本位置信息(应对排版复杂的PDF)
如果你的PDF里键值对不是同一行,比如键在上行、值在下行,或者分栏排版,光靠字符串就不够准了。这时候可以自定义PDFTextStripper子类来获取每个文本片段的坐标,再根据位置关联键和值:
// 自定义TextStripper,用来捕获每个文本的位置信息 class PositionAwareTextStripper extends PDFTextStripper { private final List<TextPosition> allTextPositions = new ArrayList<>(); public PositionAwareTextStripper() throws IOException { super(); } @Override protected void writeString(String text, List<TextPosition> textPositions) throws IOException { allTextPositions.addAll(textPositions); super.writeString(text, textPositions); } public List<TextPosition> getAllTextPositions() { return allTextPositions; } }
然后在你的主代码里使用这个类:
File f = new File("myFile.pdf"); PDDocument doc = PDDocument.load(f); PositionAwareTextStripper stripper = new PositionAwareTextStripper(); stripper.getText(doc); // 触发文本提取,同时捕获位置信息 List<TextPosition> textPositions = stripper.getAllTextPositions(); Map<String, String> keyValueMap = new HashMap<>(); String currentKey = null; float lastKeyY = 0; for (TextPosition tp : textPositions) { String text = tp.getUnicode().trim(); if (text.startsWith("someKey")) { currentKey = text; lastKeyY = tp.getY(); // 记录当前键的y坐标 } else if (currentKey != null) { // 这里根据实际排版调整位置判断逻辑,比如值和键的y坐标接近,x坐标更大 if (Math.abs(tp.getY() - lastKeyY) < 5) { // 假设y坐标差小于5就算同一行 keyValueMap.put(currentKey, text); currentKey = null; } } } doc.close();
这个方法需要你根据PDF的实际排版来调整坐标判断的阈值,比如y坐标差多少算同一行,x坐标多少算键的右侧值。
内容的提问来源于stack exchange,提问作者chebad
相关产品推荐
相关产品推荐

