如何使用iText提取PDF文档中的各级标题?
用iText提取PDF层级标题的实现思路
嘿,我来给你梳理几个用iText提取PDF层级标题的可行思路,结合你现有的代码展开说说:
思路一:基于文本格式特征识别标题
标题通常有明显的格式特征——比如更大的字号、加粗样式、特定颜色,或者固定的缩进位置。你当前用的SimpleTextExtractionStrategy只能提取纯文本,没法获取格式信息,所以可以换成自定义的文本提取策略,通过TextRenderInfo获取每个文本块的字体、字号、位置等属性,再筛选出符合标题特征的内容,最后根据格式差异区分层级(比如一级标题字号最大,二级次之)。
示例代码(适配iText 5):
// 自定义策略,检测带格式特征的标题 class HeadingDetectionStrategy extends LocationTextExtractionStrategy { @Override public void renderText(TextRenderInfo renderInfo) { // 获取文本块的字号 float fontSize = renderInfo.getFontSize(); // 判断是否为加粗字体(通过字体名称识别,不同字体命名可能有差异) boolean isBold = renderInfo.getFont().getFontName().contains("Bold"); String text = renderInfo.getText().trim(); // 自定义规则:比如字号>14且加粗,同时文本不为空 if (fontSize > 14 && isBold && !text.isEmpty()) { // 这里可以进一步根据Y轴位置(标题通常在页面上方)或缩进判断层级 System.out.println("疑似一级标题:" + text); } else if (fontSize > 12 && isBold && !text.isEmpty()) { System.out.println("疑似二级标题:" + text); } super.renderText(renderInfo); } } // 在你的循环中替换为自定义策略 for(int i = 1; i <= pdfReader.getNumberOfPages(); i++){ HeadingDetectionStrategy headingStrategy = new HeadingDetectionStrategy(); parser.processContent(i, headingStrategy); }
思路二:利用Tagged PDF的结构树提取(最准确)
如果你的目标PDF是带标签的PDF(Tagged PDF),文档内部会定义Heading1、Heading2这类结构化元素,直接读取结构树就能精准获取标题和层级,不需要依赖格式猜测。iText提供了遍历结构树的API,能直接定位到标题节点。
示例代码(适配iText 5):
PdfDocument pdfDoc = new PdfDocument(pdfReader); PdfStructTreeController structTreeController = new PdfStructTreeController(pdfDoc); PdfStructElem rootElem = structTreeController.getRoot(); // 递归遍历结构树,提取标题 traverseStructElements(rootElem, 1); // 递归处理结构元素的方法 private void traverseStructElements(PdfStructElem elem, int level) { if (elem == null) return; // 获取元素的角色(比如Head1、Head2,不同PDF的命名可能略有不同) PdfName role = elem.getRole(); if (PdfName.Head1.equals(role) || role.toString().startsWith("Head")) { // 提取标题文本 String headingText = PdfTextExtractor.getTextFromElement(elem); System.out.println("层级" + level + "标题:" + headingText); } // 遍历子元素,层级+1 for (PdfObject kid : elem.getKids()) { if (kid instanceof PdfStructElem) { traverseStructElements((PdfStructElem) kid, level + 1); } } }
注意:这个方法仅适用于带标签的PDF,普通无标签PDF无法使用。
思路三:基于标题编号规则识别
如果你的PDF标题都遵循类似1、1.1、1.2.1的编号规则,可以先提取页面纯文本,再用正则表达式匹配符合编号格式的行,通过编号中点的数量判断层级(比如1是1级,1.1是2级,1.2.1是3级)。
示例代码:
for(int i = 1; i <= pdfReader.getNumberOfPages(); i++){ TextExtractionStrategy strategy = parser.processContent(i, new SimpleTextExtractionStrategy()); String pageText = strategy.getResultantText(); // 按行分割文本(注意有些PDF换行符是\n或\r\n,需根据实际调整) String[] lines = pageText.split("\\r?\\n"); // 匹配编号开头的标题:数字+可选的.数字,后面跟空格和标题文本 Pattern headingPattern = Pattern.compile("^(\\d+(\\.\\d+)*)\\s+(.+)"); for (String line : lines) { String trimmedLine = line.trim(); Matcher matcher = headingPattern.matcher(trimmedLine); if (matcher.find()) { String numbering = matcher.group(1); String titleContent = matcher.group(3); // 计算层级:编号中点的数量+1 int level = numbering.split("\\.").length; System.out.println("层级" + level + "标题:" + titleContent); } } }
这个方法的优势是不需要依赖格式,只要编号规范就能识别,但如果标题没有编号或者编号不统一,效果会大打折扣。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

