解析PDF时出现奇怪的空格

10

我需要解析一个PDF文档。我已经实现了解析器并使用了库 iText,到目前为止它一直没有出现任何问题。

但是现在我需要解析另一个文档,其中单词之间会有非常奇怪的空格。例如:

Vo rber eitung auf die Motorr adsaison. Viele Motorr adf ahr er

所有加粗的单词都应该连在一起,但是 PDF 解析器却在单词中添加了空格。但是当我将内容从 PDF 复制并粘贴到文本文件中时,我却没有得到这些空格。

起初我以为是因为我使用的 PDF 解析库的问题,但是我使用另一个库仍然存在相同的问题。

我查看了解析后的单词中的 singleSpaceWidth,发现当它添加空格时,它总是变化的。我尝试手动将它们连接在一起。但由于没有真正的模式来重新组合单词,这几乎是不可能的。

是否有其他人遇到过类似的问题或者甚至有解决这个问题的方法呢?

如请求所示,这里有更多的信息:

使用 SemTextExtractionStrategy 进行解析:

PdfReader reader = new PdfReader("data/SpecialTests/SuedostSchweiz/" + src);

SemTextExtractionStrategy semTextExtractionStrategy = new SemTextExtractionStrategy();

for (int i = 1; i <= reader.getNumberOfPages(); i++) {
    // Set the page number on the strategy. Is used in the Parsing strategies.
    semTextExtractionStrategy.pageNumber = i;

    // Parse text from page
    PdfTextExtractor.getTextFromPage(reader, i, semTextExtractionStrategy);
}

这里是SemTextExtractionStrategy方法,实际上是解析文本。我在每个解析出的单词之后手动添加了一个空格,但是它似乎在检测时仍然分割了单词:

@Override
public void parseText(TextRenderInfo renderInfo, int pageNumber) {      

    this.pageNumber = pageNumber;

    String text = renderInfo.getText();

    currTextBlock.getText().append(text + " ");

    ....
}

以下是整个SemTextExtraction类,但它仅调用上面的方法(parseText):

public class SemTextExtractionStrategy implements TextExtractionStrategy {

    // Text Extraction Strategies
    public ColumnDetecter columnDetecter = new ColumnDetecter();

    // Image Extraction Strategies
    public ImageRetriever imageRetriever = new ImageRetriever();

    public int pageNumber = -1;

    public ArrayList<TextParsingStrategy> textParsingStrategies = new ArrayList<TextParsingStrategy>();
    public ArrayList<ImageParsingStrategy> imageParsingStrategies = new ArrayList<ImageParsingStrategy>();

    public SemTextExtractionStrategy() {

        // Add all text parsing strategies which are later on applied on the extracted text
        // textParsingStrategies.add(fontSizeMatcher);
        textParsingStrategies.add(columnDetecter);

        // Add all image parsing strategies which are later on applied on the extracted text
        imageParsingStrategies.add(imageRetriever);
    }

    @Override
    public void beginTextBlock() {

    }

    @Override
    public void renderText(TextRenderInfo renderInfo) {
        // TEXT PARSING
        for(TextParsingStrategy strategy : textParsingStrategies) {
            strategy.parseText(renderInfo, pageNumber);
        }
    }

    @Override
    public void endTextBlock() {

    }

    @Override
    public void renderImage(ImageRenderInfo renderInfo) {
        for(ImageParsingStrategy strategy : imageParsingStrategies) {
            strategy.parseImage(renderInfo);
        }
    }
}

@tobaiasjl 那是很久以前的事了... 但我有点记得 PDF 文件已经损坏,使用新生成的 PDF 文件问题就不会再出现了。 - Prine
@Prine,你是如何重新生成PDF的? - NinjaOnSafari
如果我没记错的话,它最初是一个Word文档,我们用另一个Word版本重新创建了它。但不是100%确定,那是3年前的事;) - Prine
@Prine 嗯,真遗憾我不能这样做...你知道下面的那个人用什么来生成PDF吗? - NinjaOnSafari
@NinjaOnSafari 好吧,他在终端中使用了“gs”命令,但你需要向他询问更多细节... - Prine
显示剩余4条评论
3个回答

6

PDF中的空格是一个已知的问题,如Roland在这里的回答所描述的那样,并且也可以在https://issues.apache.org/jira/browse/TIKA-724的第一条评论中看到。

对我也起作用的答案是由huuhungus在https://github.com/smalot/pdfparser/issues/72中提出的,它是针对PDFParser的,并且是要更改实际向PDFParser添加此额外空格的代码,如果您知道您将遇到此问题:

src/Smalot/PdfParser/Object.php comment out this line

   $text .= ' ';

Not completely fix it, but it's at acceptable

其他库也可能有类似的临时解决方案,因此在某些情况下它们可以帮助解决此问题。


iText 5.2.1现在已经是一个古老的版本了。当前版本具有属性/可重写方法,可以微调iText添加空格的情况。总体上,从不添加空格也是一个糟糕的选择,因为许多PDF文件的文本提取几乎没有任何空格。 - mkl

5

我通过以下Ghostscript命令处理了给定的PDF文件:

gs -o out.pdf -q -sDEVICE=pdfwrite -dOptimize=false -dUseFlageCompression=false -dCompressPages=false -dCompressFonts=false whitespacesProblem.pdf

这个命令创建了一个名为out.pdf的文件,没有流编码,因此更易读。有趣的部分在第52行,我将其拆分成多行以提高可读性。
[
  (&;&)-287.988
  (672744)29.9906
  (+\(%)30.01
  (+!4)29.9876
  (&4)-287.989
  (%4)30.0039
  (&1&8)-287.975
  (3=\)!)-288.021
  (*&4)30.0212
  (&=23)-287.996
  (+1%)-287.99
  (\(=&)-288.011
  (8&1&)-287.974
  (672744)29.9906
  (+\(3+=378$)-250.977
  (#7\)!)
]TJ

圆括号内是文本字符。我更改了其中一些,并观察渲染的PDF文件,以查看哪个字符代表哪个字形。然后我解码了文本:

[
  (ele)-287.988
  (Motorr)29.9906 ***
  (adf)30.01 ***
  (ahr)29.9876 ***
  (er)-287.989
  (fr)30.0039
  (euen)-287.975
  (sich)-288.021
  ...
]

因此,字符之间确实存在空白。在您的情况下,这可能是字体紧排的结果。现在问题是,您的PDF库如何解释这个空白,我觉得即使是“负空白”,也会被渲染成结果字符串中的一个空格。


有没有一种方法可以摆脱这个问题或实现它? - NinjaOnSafari
你用了什么工具生成PDF文件? - NinjaOnSafari
这是Ghostscript;我已经编辑了答案以明确这一点。谢谢提示。 - Roland Illig
无法消除PDF文件中的空格,因为它就在那里。我不知道iText是否可以处理此问题以及如何处理,因为我不了解iText。在这个答案中,我只是解释了额外的空格来自哪里。 - Roland Illig

0
因为您拥有的文档被分成了列,明显的错误在于

SemTextExtractionStrategy

类中。我猜测 ColumnDetecter 类可能是有问题的,而不是 iText 的问题。我只能假设它是基于列的大小来实现的,然后根据此检索文本。

如果您只想要文本,则实现可以更简单,基于列的大小。


谢谢你的回答。我一定会查看ColumnDetecter。但是parseText方法来自这个类,我直接从iText库中获取输出,其中单词已经被分割了。 - Prine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接