Java 如何使用iText解析未标记的pdf文件

Java 如何使用iText解析未标记的pdf文件,java,pdf,itext,pdf-parsing,Java,Pdf,Itext,Pdf Parsing,我想用iText解析这个文件()。问题是它没有标记,所以我无法获取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

我想用iText解析这个文件()。问题是它没有标记,所以我无法获取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查看器如何知道加拿大在第二列而不是第三列

我目前的解决方案是使用谁能确定每一列的文本,将pdf文件转换为html5

感谢您的回复

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

这是一个错误的问题,但是“为什么”包含了可能的解决方案的提示

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

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

一种可能的解决方案是存储所有文本片段的所有(x,y)坐标,对它们进行排序,然后测试每个文本片段的结尾与下一个文本片段的开始是否在合理的距离内。(这也需要检索字符宽度。)如果距离或多或少等于空格宽度,则可以输出“空格”。如果更多,您可以输出一个[选项卡]。下面是一个简单的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
--为了清晰起见,我手动对齐了各个列,因为每个列之间只有一个[选项卡]。您的文档很容易,因为每一列都包含一些文本。如果不这样做的话,就更难了(但如果必要的话,您可以创建一个可能的选项卡位置列表,并根据该列表测试每个新的文本字符串)

简而言之,您不能使用普通函数
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
2020 LALAWW Anand and ORDEORDER:SR:SVUVU CTVv TTototatal..WW。。。。21:0021:00 23:0023:00 12951295

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

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

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

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

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


如果您提出了一个好的、通用的想法(即不特定于这项解析任务),请告诉我,我将看看我能做些什么来将其整合到iText中。

非常感谢,我今天学到了一些东西。对于解决方案,我已经按照你的建议做了。库JPedal可以检索列,但您必须付费。您知道如何在iText上报告错误吗?我为什么会知道?:-)1.这不是一个解析或提取错误;该文本在PDF中存储两次。2.我没有使用iText,我从头开始编写了自己的PDF解析器我不知道iText的默认文本转换器有多智能;我打赌它也会输出这个字符串两次