2

我想用 iText解析这个文件( http://www.bbm.ca/_documents/top_30_tv_programs_english/2011/nat01032011.pdf )。问题是它没有标记,所以我无法获取 XML 文件。我决定从中提取文本,我认为例如第一行将是:

1\specialCharWJC:PLAYOFFS CANADA\specialCharTSN+\specialCharM.W....\specialChar19:30\specialChar21:57\specialChar5133

我为第一行提取的文本是

1 WJC:PLAYOFFS CANADA TSN+ M.W.... 19:30 21:57 5133

我使用以下方法提取了文本:

PdfReader reader = new PdfReader(filename);
String str = PdfTextExtractor.getTextFromPage(reader, 1);

PDF 查看器如何知道加拿大在第二列而不是第三列。

我目前的解决方案是使用http://www.idrsolutions.com/online-pdf-to-html5-converter/将 pdf 文件转换为 html5 ,它可以确定每列的文本。

感谢您的答复

4

2 回答 2

5

我编写了 iText 文本提取器。iText 中有两种提取策略 - 一种是幼稚的(更多的概念证明),它只是在遇到文本时转储文本。另一个(LocationTextExtractionStrategy)更加完善,它使用@Jongware 建议的位置和字体信息构建字符串(它还考虑了所有坐标转换)。如果您只是像您一样调用 getTextFromPage() ,则后者是默认策略。

第 20 行文本显示两次的原因是 b/c 一些 PDF 制作者这样做是为了模拟粗体字形(他们稍微移动字符并重新渲染)。所以这不是一个错误,真的 - 但肯定是一个改进的机会。如果我们检测到大块相同的内容落在彼此的某个缇区域内,我们可能会做一些事情。我们还没有这样做的原因是这可能真的很棘手,b/c 你可能有一个块是整个单词,还有另一组块——每个字母一个块。我们有能力进行子块分析(事实上,这在解析器接口中的某个地方暴露了 - 无法立即回忆 - 如果你需要它,请告诉我,我会追踪它) - 但那会来性能损失相当大,所以我不愿意这样做。

无论如何,我解决这个特定挑战的方法是设置物理区域并将区域过滤器传递给 LocationTextExtractionStrategy#getResultantText() 调用。

如果您确实需要根据文本的水平位置插入制表符(或某些列标记),这是非常可行的 - 看看在 LocationTextExtractionStrategy 源代码中调用 isChunkAtWordBoundary() 方法的位置并添加您自己的处理程序用于在空格之外插入特殊字符。也可以进行某种上下文分析(即注意有一堆碰巧共享相同 X 位置和方向的块,并将该 X 位置指定为制表位)。

如果您想出一个很好且通用的想法(即不特定于这个解析任务),请告诉我,我会看看我能做些什么来将它合并到 iText 中。

于 2014-01-26T03:52:27.953 回答
3

这 ...

PDF 查看器如何知道加拿大在第二列而不是第三列。

是错误的问题——但“为什么”包含可能解决方案的提示。

这个问题是“错误的”,因为您的“PDF 查看器”不知道文本应该在第二列中。PDF 中没有“勺子”列:查看者得到的只是 (x,y) 位置列表和要在其上显示的文本。它所要做的就是将光标移动到 (x,y) 位置并绘制文本。看?不涉及列。也不是一个 [Tab] 字符(或任何其他类型的魔法\specialChar,就此而言)。

一个愚蠢的、直接的文本转换器扫描输入文件中的文本运行并立即将它们写出。它可能会测试大于预期的 x 位置,并在必要时插入一个空格 - 事实上,iText 似乎这样做是因为检查您的文件显示在“1”和“WJC”之间没有存储“空格”字符:季后赛加拿大”。在相同的 y 位置移动到更大的 x 位置,因此 iText 推断存在“某些东西”。

一种可能的解决方案是存储所有文本片段的所有 (x,y) 坐标,对它们进行排序,然后测试每个文本片段的结尾是否在下一个开头的合理距离内。(这也需要您检索字符宽度。)如果距离或多或少等于空格宽度,则可以输出“空格”。如果更多,您可以输出一个[Tab]。以下是执行此操作的简单 PDF 阅读器的输出:

1   WJC:PLAYOFFS CANADA     TSN+        M.W.... 19:30   21:57   5133
2   WJC:PLYOFF CAN PSTGM    TSN+        ..W.... 21:54   22:21   3558
3   BIG BANG THEORY         CTV Total   ...T... 20:00   20:31   3334

-- 为了清楚起见,我手动对齐了列,因为每列之间只有一个 [Tab]。您的文档很“简单”,因为每一列都包含一些文本。如果没有,它会稍微困难一些(但如果有必要,您可以创建一个可能的制表符位置列表,并针对它测试每个新的文本字符串)。

简而言之,您不能使用普通函数getTextFromPage,您需要检索正确的 x 和 y 位置并进行处理。


令人惊讶的是:出于某种未知原因,这条线

20  LAW AND ORDER:SVU   CTV Total   W   21:00   23:00   1295

本文档在完全相同的位置包含两次。我没有预料到,所以在排序后,我在输出中得到了这个:

20<FONT ArialMT>20 LALAWW ANANDD ORDEORDER:SR:SVUVU CTCTVV TTotalotal ..WW.... 21:0021:00 23:0023:00 1295<FONT Arial-BoldMT>1295

更简单的解决方案

...将是手动创建“广播网点”列表。该列表具有相当可预测的格式:([digits] [Title] [Outlet] ..等),并且只有 Title 和 Outlet 不遵循特定模式。在这个列表中,我只计算了 4 家不同的广播公司。解析剩余的“列”应该很简单。

于 2014-01-25T20:36:17.517 回答