Java: Apache POI: Могу ли я получить чистый текст из файлов MS Word (.doc)?

Строки, которые я (программно) получаю из файлов MS Word при использовании Apache POI, - это не тот текст, на который я могу смотреть, когда открываю файлы в MS Word.

При использовании следующего кода:

File someFile = new File("some\\path\\MSWFile.doc");
InputStream inputStrm = new FileInputStream(someFile);
HWPFDocument wordDoc = new HWPFDocument(inputStrm);
System.out.println(wordDoc.getText());

вывод представляет собой одну строку с множеством «недопустимых» символов (да, «квадраты») и множеством нежелательных строк, таких как «FORMTEXT», «HYPERLINK \l "_Toc##########"» («#» - это числовые цифры), «PAGEREF _Toc########## \h 4» и т. д.

Следующий код «исправляет» проблему с одной строкой, но сохраняет все недопустимые символы и нежелательный текст:

File someFile = new File("some\\path\\MSWFile.doc");
InputStream inputStrm = new FileInputStream(someFile);
WordExtractor wordExtractor = new WordExtractor(inputStrm);
for(String paragraph:wordExtractor.getParagraphText()){
  System.out.println(paragraph);
}

Я не знаю, использую ли я неправильный метод извлечения текста, но это то, что я придумал, глядя на Краткое руководство по POI. Если да, то каков правильный подход?

Если результат верен, существует ли стандартный способ избавиться от нежелательного текста или мне придется написать собственный фильтр?


person XenoRo    schedule 20.04.2012    source источник


Ответы (3)


Есть два варианта: один предоставляется непосредственно в Apache POI, другой - через Apache Tika (который внутренне использует Apache POI).

Первый вариант - использовать WordExtractor, но заключить его в вызов _ 2_ при его вызове. Это приведет к удалению текстовых полей, включенных в текст, таких как ГИПЕРССЫЛКА, которую вы видели. Ваш код станет:

NPOIFSFileSystem fs = new NPOIFSFileSytem(file);
WordExtractor extractor = new WordExtractor(fs.getRoot());

for(String rawText : extractor.getParagraphText()) {
String text = extractor.stripFields(rawText);
System.out.println(text);
}

Другой вариант - использовать Apache Tika. Tika обеспечивает извлечение текста и метаданных для самых разных файлов, поэтому один и тот же код будет работать и с .doc, .docx, .pdf и многими другими. Чтобы получить чистый, простой текст вашего текстового документа (вы также можете получить XHTML, если хотите), вы должны сделать что-то вроде:

TikaConfig tika = TikaConfig.getDefaultConfig();
TikaInputStream stream = TikaInputStream.get(file);
ContentHandler handler = new BodyContentHandler();
Metadata metadata = new Metadata();
tika.getParser().parse(input, handler, metadata, new ParseContext());
String text = handler.toString();
person Gagravarr    schedule 22.04.2012
comment
Второе решение не сработало в моих тестах. TIKA-1.2 вернул FORMCHECKBOX и другие вещи из файлов .doc. Однако файлы .docx работали нормально. - person Simon; 07.02.2013
comment
Я предлагаю вам попробовать самую последнюю версию Tika, 1.3. Если проблема не исчезнет, ​​сообщите об ошибке и загрузите образец файла с ее отображением. , так что мы можем исследовать! - person Gagravarr; 07.02.2013
comment
Это все еще происходит в Tika 1.3 для меня, чего стоит. - person damd; 22.02.2013
comment
Тогда вам лучше всего сообщить об ошибке в Apache Tika и включить файл, который показывает проблему. - person Gagravarr; 22.02.2013

Этот класс может читать файлы .doc и .docx в Java. Для этого я использую tika-app-1.2.jar:

/*
 * This class is used to read .doc and .docx files
 * 
 * @author Developer
 *
 */

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL; 
import org.apache.tika.detect.DefaultDetector;
import org.apache.tika.detect.Detector;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.ContentHandler;

class TextExtractor { 
    private OutputStream outputstream;
    private ParseContext context;
    private Detector detector;
    private Parser parser;
    private Metadata metadata;
    private String extractedText;

    public TextExtractor() {
        context = new ParseContext();
        detector = new DefaultDetector();
        parser = new AutoDetectParser(detector);
        context.set(Parser.class, parser);
        outputstream = new ByteArrayOutputStream();
        metadata = new Metadata();
    }

    public void process(String filename) throws Exception {
        URL url;
        File file = new File(filename);
        if (file.isFile()) {
            url = file.toURI().toURL();
        } else {
            url = new URL(filename);
        }
        InputStream input = TikaInputStream.get(url, metadata);
        ContentHandler handler = new BodyContentHandler(outputstream);
        parser.parse(input, handler, metadata, context); 
        input.close();
    }

    public void getString() {
        //Get the text into a String object
        extractedText = outputstream.toString();
        //Do whatever you want with this String object.
        System.out.println(extractedText);
    }

    public static void main(String args[]) throws Exception {
        if (args.length == 1) {
            TextExtractor textExtractor = new TextExtractor();
            textExtractor.process(args[0]);
            textExtractor.getString();
        } else { 
            throw new Exception();
        }
    }
}

Скомпилировать:

javac -cp ".:tika-app-1.2.jar" TextExtractor.java

Бежать:

java -cp ".:tika-app-1.2.jar" TextExtractor SomeWordDocument.doc
person Vyas    schedule 17.08.2012

Попробуйте это, работает для меня и является исключительно решением для POI. Однако вам придется искать аналог HWPFDocument. Убедитесь, что документ, который вы читаете, предшествует Word 97, иначе используйте XWPFDocument, как я.

InputStream inputstream = new FileInputStream(m_filepath); 
//read the file 
XWPFDocument adoc= new XWPFDocument(inputstream);
//and place it in a xwpf format

aString = new XWPFWordExtractor(adoc).getText();           
//gets the full text

Теперь, если вам нужны определенные части, вы можете использовать getparagraphtext, но не используйте экстрактор текста, используйте его непосредственно в абзаце, как это

for (XWPFParagraph p : adoc.getParagraphs()) 
{ 
    System.out.println(p.getParagraphText());
}
person Steven Bellens    schedule 04.11.2014