gpt4 book ai didi

java - 如何使用 PDFBox 从 PDF 中提取数据时用单词替换空格

转载 作者:行者123 更新时间:2023-11-30 01:54:26 26 4
gpt4 key购买 nike

我想用一个单词替换任何空列;例如,提取 Pdf 数据时出现单词BLK

下表是预期表和实际结果的示例。

原始表

+--------------------------------------+
|# |NAME |TEL |GENDER |
|---------------------------|----------|
|1 |JOHN |096587498 |M |
|2 |VILLA | |F |
+--------------------------------------+

预期结果

# NAME TEL GENDER
1 JOHN 096587498 M
2 VILLA BLK F

实际结果

# NAME TEL GENDER
1 JOHN 096587498 M
2 VILLA F

实际结果来自PDFTextStripper类。

捕获 pdf 文件 enter image description here

最佳答案

PDFTextStripper看不到 PDF 中的图形线,它只能看到文本字符。因此,在第 2 行中,它会看到“2”、“Villa”和“F”,中间有间隙。因此,仅靠这个类(class),你不会得到你想要的。

一般来说,使用 PDFBox 有以下选项:

  • 您可以首先尝试通过解析页面的 vector 图形指令来识别 PDF 中的表格单元格区域,然后逐个单元格地提取文本。

    This answer为此提供了概念验证。注意:这个答案重点关注该问题的OP提供的示例文档。特别是,它希望将线条绘制为细实心矩形;对于通用解决方案,需要扩展收集表格线的代码,以识别以其他方式绘制的线。

    这种方法显然需要用行(或者通过扩展或者用背景颜色或类似的东西来划分)表格的行和列;但情况并非总是如此。

    对于您的示例文档,代码可以开箱即用:

    [A1] # 

    [A2] Name

    [A3] Tel

    [A4] Gender

    [B1] 1

    [B2] John

    [B3] 096875959

    [B4] M

    [C1] 2

    [C2] Villa

    [C3]

    [C4] F

    (ExtractBoxedText测试testExtractBoxedTextsTestWPhromma的输出)

  • 您可以提取尝试反射(reflect) PDF 布局的文本。如果您知道相关表格的总体布局(第 n 列从这里到那里...),您可以导出表格单元格内容。

    This answer为布局感知文本提取提供了概念验证。请注意,代码基于 PDFBox 1.8.x,可能需要进行一些调整。

    此方法需要了解表格列布局;这并不总是给出。

    对于您的示例文档,代码可以开箱即用:

                     #              Name                                                            Tel                                    Gender
    1 John 096875959 M
    2 Villa F

    (ExtractTextWithLayout测试testExtractTestWPhromma的输出)

  • 对于带标签的 PDF,您可以尝试提取文本,包括反射(reflect)表格结构的标签(如果标签正确)。

    随着您的示例文档被标记,我将在下面展示一个快速而肮脏的概念证明。

    此方法需要对 PDF 进行正确标记;但情况并非总是如此。

提取带有标签的内容

如果您的 PDF 已正确标记,您可以提取包括标记标签的内容,如下所示:

PDDocument document = PDDocument.load(SOURCE);

Map<PDPage, Map<Integer, PDMarkedContent>> markedContents = new HashMap<>();

for (PDPage page : document.getPages()) {
PDFMarkedContentExtractor extractor = new PDFMarkedContentExtractor();
extractor.processPage(page);

Map<Integer, PDMarkedContent> theseMarkedContents = new HashMap<>();
markedContents.put(page, theseMarkedContents);
for (PDMarkedContent markedContent : extractor.getMarkedContents()) {
theseMarkedContents.put(markedContent.getMCID(), markedContent);
}
}

PDStructureNode root = document.getDocumentCatalog().getStructureTreeRoot();
showStructure(root, markedContents);

( ExtractMarkedContent 测试 testExtractTestWPhromma )

使用这两个辅助方法

void showStructure(PDStructureNode node, Map<PDPage, Map<Integer, PDMarkedContent>> markedContents) {
String structType = null;
PDPage page = null;
if (node instanceof PDStructureElement) {
PDStructureElement element = (PDStructureElement) node;
structType = element.getStructureType();
page = element.getPage();
}
Map<Integer, PDMarkedContent> theseMarkedContents = markedContents.get(page);
System.out.printf("<%s>\n", structType);
for (Object object : node.getKids()) {
if (object instanceof COSArray) {
for (COSBase base : (COSArray) object) {
if (base instanceof COSDictionary) {
showStructure(PDStructureNode.create((COSDictionary) base), markedContents);
} else if (base instanceof COSNumber) {
showContent(((COSNumber)base).intValue(), theseMarkedContents);
} else {
System.out.printf("?%s\n", base);
}
}
} else if (object instanceof PDStructureNode) {
showStructure((PDStructureNode) object, markedContents);
} else if (object instanceof Integer) {
showContent((Integer)object, theseMarkedContents);
} else {
System.out.printf("?%s\n", object);
}

}
System.out.printf("</%s>\n", structType);
}

void showContent(int mcid, Map<Integer, PDMarkedContent> theseMarkedContents) {
PDMarkedContent markedContent = theseMarkedContents != null ? theseMarkedContents.get(mcid) : null;
List<Object> contents = markedContent != null ? markedContent.getContents() : Collections.emptyList();
StringBuilder textContent = new StringBuilder();
for (Object object : contents) {
if (object instanceof TextPosition) {
textContent.append(((TextPosition)object).getUnicode());
} else {
textContent.append("?" + object);
}
}
System.out.printf("%s\n", textContent);
}

(ExtractMarkedContent辅助方法)

示例 PDF 的输出

enter link description here

<null>
<Document>
<Table>
<THead>
<TR>
<TH>
<P>
#
</P>
</TH>
<TH>
<P>
Name
</P>
</TH>
<TH>
<P>
Tel
</P>
</TH>
<TH>
<P>
Gender
</P>
</TH>
</TR>
</THead>
<TBody>
<TR>
<TH>
<P>
1
</P>
</TH>
<TD>
<P>
John
</P>
</TD>
<TD>
<P>
096875959
</P>
</TD>
<TD>
<P>
M
</P>
</TD>
</TR>
<TR>
<TH>
<P>
2
</P>
</TH>
<TD>
<P>
Villa
</P>
</TD>
<TD>
<P>

</P>
</TD>
<TD>
<P>
F
</P>
</TD>
</TR>
</TBody>
</Table>
<P>

</P>
</Document>
</null>

您认识到空单元格:

<TD>
<P>

</P>
</TD>

此概念验证提取到标准输出。显然,您可以选择在字符串生成器或流中收集数据,或者可以填充 <Table>数据立即进入自定义结构,它们毕竟已经在单元格中分开。

注意:这只是一个概念验证。代码输出这样的数据 System.out.printf("?%s\n", ...); ,可能需要一些特定的处理。其他边界条件也可能没有得到充分考虑。 (实际上,我实现它只是为了正确提取示例 PDF 的内容。)

关于java - 如何使用 PDFBox 从 PDF 中提取数据时用单词替换空格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54956720/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com