Странные пробелы при анализе PDF

мне нужно проанализировать 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);
        }
    }
}

3 ответов


я обработал данный PDF-файл со следующим Ghostscript:

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-файлом, чтобы узнать, какой символ представляет глиф. Затем я расшифровал текст:--7-->

[
  (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 интерпретирует этот пробел, и мне кажется, что даже "отрицательные пробелы" отображаются в пробел в результирующей строке.


пробелы в pdf являются известной проблемой, как описано в ответе здесь Роландом, а также видно при первом комментарии https://issues.apache.org/jira/browse/TIKA-724

ответ, который также работал для меня, - это тот, который видел huuhungus на https://github.com/smalot/pdfparser/issues/72

который специфичен для PDFParser, и он должен изменить код, который фактически добавляет Это дополнительное пространство в PDFParser, если вы знаете, что у вас будет такая проблема:

src/Smalot/PdfParser / Object.php прокомментируйте эту строку

   $text .= ' ';

не полностью исправить, но это на приемлемом

другие библиотеки также могут иметь аналогичные временные исправления, чтобы они могли помочь с этой проблемой в некоторых случаях.


поскольку документ, который у вас есть, разбит на столбцы, очевидная ошибка находится внутри

SemTextExtractionStrategy

класса. Я предполагаю, что класс ColumnDetecter надо винить, наверное, и не iText. Я могу только предположить, что он реализован на основе размера столбца, а затем извлекает текст на основе этого.

Если вы хотите только текст, то реализация может быть проще, на основе о размере столбца.