除了 Chris 的通用答案,iText(Sharp) 内容解析的一些背景......
iText(Sharp) 为/中的内容提取提供了一个框架。该框架读取页面内容,跟踪当前图形状态,并将有关内容片段的信息转发给或/或用户(即您)提供。特别是它不会将结构解释为该信息。namespace iTextSharp.text.pdf.parser
package com.itextpdf.text.pdf.parser
IExtRenderListener
IRenderListener
ExtRenderListener
RenderListener
该渲染侦听器可以是文本提取策略 ( ITextExtractionStrategy
/ TextExtractionStrategy
),即主要设计用于提取纯文本流而没有格式或布局信息的特殊渲染侦听器。对于这种特殊情况,iText(Sharp) 还提供了两个示例实现,theSimpleTextExtractionStrategy
和LocationTextExtractionStrategy
.
对于您的任务,您需要一个更复杂的渲染侦听器,它要么
- 导出带有坐标的文本(Chris在他的一个答案中提供了一个扩展
LocationTextExtractionStrategy
,它可以额外提供文本块的位置和边界框),允许您在附加代码中分析表格结构;或者
- 对表格数据本身进行分析。
我没有后一种变体的示例,因为一般识别和解析表本身就是一个完整的项目。您可能想从Tabula项目中寻找灵感;这个项目非常擅长表格提取任务。
PS:如果您对尝试从内容的纯字符串表示中提取结构化内容感到更加自在,但仍试图反映原始布局,您可以尝试类似此答案中提出的内容,这是工作的变体,LocationTextExtractionStrategy
类似于pdftotext -layout
工具;那里只显示要应用于的更改LocationTextExtractionStrategy
。
PPS:从非常具体的 PDF 表中提取数据可能会容易得多;例如,看看这个答案,它表明在一些 PDF 分析之后,创建给定表的特定方式可能会产生一个简单的自定义渲染侦听器来提取表数据。这对于具有跨越许多页面的表格的单个 PDF 是有意义的,例如在该答案的情况下,或者如果您有许多由同一软件创建的相同的 PDF,这可能是有意义的。
这就是为什么我在对您的问题的评论中要求提供具有代表性的示例文件
关于您的评论
仍然使用上面的 pdf 示例,从头开始实现 ITextExtractionStrategy 和扩展 LocationExtractionStrategy,我看到每个 RenderText 在以下块中调用:Fi、el、d、A、Fi、el、d... 等等在。这可以改变吗?
您作为单独调用获得的文本块RenderText
不会因意外或 iText 的某些随机决定而分离。它们是页面内容中单独绘制的字符串!
在您的示例中,“Fi”、“el”、“d”和“A”有不同RenderText
的调用,因为内容流包含首先绘制“Fi”,然后是“el”,然后是“d”,然后是“一种”。
起初这可能听起来很奇怪。造成这种撕裂的一个常见原因是 PDF 不使用字体中的字距调整信息。因此,要应用字距调整,PDF 生成软件必须在字符之间插入微小的向前或向后跳转,这些字符之间的距离应该比没有字距调整的距离更远或更近。因此,单词经常在字距调整对之间被撕裂。
所以这是不能改变的,你会得到这些碎片,文本提取策略的工作就是把它们放在一起。
顺便说一句,还有一些更糟糕的 PDF,一些 PDF 生成器分别定位每个字形,最重要的是这些生成器主要构建 GUI,但可以作为一个功能自动将 GUI 画布导出为 PDF。
我希望在进入“添加我自己的实现”的领域时,我可以控制如何确定什么是文本“块”。
你可以……嗯,你必须决定哪些传入的部分属于一起,哪些不属于。例如,具有相同 y 坐标的字形是否形成单行?或者它们是否在恰好位于彼此相邻的不同列中形成单独的行。
所以是的,您决定将哪些字形解释为单个单词或单个表格单元格的内容,但您的输入由实际 PDF 内容流中使用的字形组组成。
不仅如此,在界面的任何方法中,我都无法“发现”它如何/在何处处理非文本数据/图像 - 所以我可以解决间距问题(不调用 RenderImage)
RenderImage
将调用嵌入式位图图像、JPEG 等。如果您想了解矢量图形,您的策略还必须实现IExtRenderListener
which provides methodsModifyPath
和.RenderPath
ClipPath