Я обнаружил проблему при синтаксическом анализе документов PDF, отправленных веб-службе для NLP. Мы используем Tika 1.19.1 для извлечения простого текста.
Некоторые люди пишут свои документы неправильно или неправильно акцентированы (на самом деле, большинство людей, использующих наш сервис, забывают добавить точку в конце абзаца), поэтому мы считаем новую строку концом предложения, это не так. не имеет значения, имеет ли он точку в конце или нет. Когда они загружают файлы в формате docx, все генерируется в ускоренном порядке: все идет в одну строку, ЕСЛИ пользователь не вводит символ новой строки вручную, его не заботит макет страницы. Это ожидаемое поведение.
Когда люди загружают файлы PDF (до сих пор каждый файл был создан MS Word), Тика генерирует дополнительные новые строки в конце нарисованной линии PDF.
Ожидаемый результат:
Это тестовый документ.
Первая строка: все содержимое этого файла должно отображаться в трех строках текста, как было написано автором. Lorem Ipsum Dolor Sit Amet, Concetetur Adipiscing Elit. Маурис в посуэре дуй. Quisque Sed Enim Commodo, Porttitor Ante Eget, Semper NISL. Сед в рутрум магна. Потенциал Suspendisse. Nulla accumsan neque eu nisi condimentum accumsan. Etiam condimentum ullamcorper nulla. Suspendisse Vel Turpis Nunc. Suspendisse eget ex quam. Lorem Ipsum Dolor Sit Amet, Concetetur Adipiscing Elit. Приостановить последовательное резюме ex в facilisis.
Вторая строка: это новая строка после первой. Неважно, если над ним есть пустая строка или сейчас (хотя это не было когда написано), важно только то, что строка заканчивается здесь, а не раньше.
Третья строка: если это не так, это означает, что Тика угадывает переводы строк, чтобы сделать .txt читабельным, однако, это разрушит обработку естественного языка, которая опирается на переводы строк для определения конца предложений, которые не были должным образом отмечены.
однако, фактический результат выглядит так:
Это тестовый документ.
Первая строка: все содержимое этого файла должно отображаться в трех строках текста, как было написано
автор. Lorem Ipsum Dolor Sit Amet, Concetetur Adipiscing Elit. Маурис в посуэре дуй.
Quisque sed enim Commodo, Porttitor Ante Eget, Semper Nisl. Сед в рутрум магна.
Потенциал приостановки. Nulla accumsan neque eu nisi condimentum accumsan. Этиам
condimentum ullamcorper nulla. Suspendisse Vel Turpis Nunc. Suspendisse eget ex quam.
Lorem Ipsum Dolor Sit Amet, Concetetur Adipiscing Elit. Suspendisse consequat vitae ex in
facilisis.
Вторая строка: это новая строка после первой. Неважно, если над ним есть пустая строка или
сейчас (хотя и не было при написании), но главное, чтобы строка здесь заканчивалась,
и не раньше.
Третья строка: если это не так, это означает, что Тика угадывает переводы строки, чтобы сделать .txt читабельным, однако это
разрушит обработку естественного языка, которая опирается на символы новой строки для определения конца предложений
, которые не были должным образом акцентированы.
ЕСЛИ вы копируете в блокнот из сгенерированного PDF, он НЕ добавляет «плохих строк»: при копировании вручную создается ожидаемый результат, поэтому я предполагаю, что PDF был сгенерирован правильно.
Примеры:
Так как создать рабочий пример очень просто, я опишу этот процесс вместо его загрузки на сервер, где он в конечном итоге умрет.
Чтобы создать пример для воспроизведения проблемы, сгенерируйте 300-500 символов lorem-ipsum в одной строке. Скопируйте эту строку в MS Word и сохраните файл. Тика будет извлекать его одной строкой. Используя MS Word, сохраните документ в формате PDF. Теперь он будет использовать столько строк, сколько использовался ваш макет страницы.
Iчувствую, что синтаксический анализатор "слишком умен" и пытается разбить строки на печатные строки, что очень удобно для чтения человеком, но так плохо для НЛП: S
Упрощенный код Tika:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.pdf.PDFParser;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.SAXException;
public class PDFParse {
public static void main(final String[] args) throws IOException,TikaException, SAXException {
BodyContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
FileInputStream inputstream = new FileInputStream(new File("D:\\Trabajo\\Document Parser\\cv_test.pdf"));
ParseContext pcontext = new ParseContext();
//parsing the document using PDF parser
PDFParser pdfparser = new PDFParser();
pdfparser.parse(inputstream, handler, metadata,pcontext);
//getting the content of the document
System.out.println("Contents of the PDF :" + handler.toString());
//getting metadata of the document
System.out.println("Metadata of the PDF:");
String[] metadataNames = metadata.names();
for(String name : metadataNames) {
System.out.println(name+ " : " + metadata.get(name));
}
}
}
PD: использование следующего упрощенного кода с PDFBox приводит к тем же ошибкам:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.pdfbox.cos.COSDocument;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.io.RandomAccessRead;
import org.apache.pdfbox.io.RandomAccessFile;
public class PDFReader{
public static void main(String args[]) {
PDFTextStripper pdfStripper = null;
PDDocument pdDoc = null;
COSDocument cosDoc = null;
File file = new File("D:\\Trabajo\\Document Parser\\lorem.pdf");
try {
// PDFBox 2.0.8 require org.apache.pdfbox.io.RandomAccessRead
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
PDFParser parser = new PDFParser(randomAccessFile);
//PDFParser parser = new PDFParser(new FileInputStream(file));
parser.parse();
cosDoc = parser.getDocument();
pdfStripper = new PDFTextStripper();
pdDoc = new PDDocument(cosDoc);
pdfStripper.setStartPage(1);
pdfStripper.setEndPage(5);
String parsedText = pdfStripper.getText(pdDoc);
System.out.println(parsedText);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}