2012-04-20 9 views
11

Die Strings, die ich (programmatisch) von MS Word-Dateien bekomme, wenn ich Apache POI verwende, sind nicht der gleiche Text, den ich betrachten kann, wenn ich die Dateien mit MS Word öffne.Java: Apache POI: Kann ich sauberen Text von MS Word (.doc) Dateien bekommen?

Wenn mit dem folgenden Code:

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

der Ausgang ist eine einzige Zeile mit vielen 'ungültig' Zeichen (ja, die 'Boxen') und viele unerwünschte Strings, wie "FORMTEXT", "HYPERLINK \l "_Toc##########" "('#' sind Ziffern)," PAGEREF _Toc########## \h 4“usw.

Der folgende Code "fixes" die einzeilige Problem, aber behält alle ungültigen Zeichen und unerwünschten Text:

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); 
} 

Ich weiß nicht, ob ich die falsche Methode zum Extrahieren des Textes verwende, aber das ist, was ich bei POI's quick-guide sah. Wenn ich bin, was ist der richtige Ansatz?

Wenn diese Ausgabe korrekt ist, gibt es eine Standardmethode, um den unerwünschten Text loszuwerden, oder muss ich einen eigenen Filter schreiben?

Antwort

6

Es gibt zwei Optionen, eine direkt in Apache POI, die andere über Apache Tika (die Apache POI intern verwendet).

Die erste Option ist die Verwendung WordExtractor, aber wickeln Sie es in einen Anruf an stripFields(String) beim Aufruf. Dadurch werden die textbasierten Felder entfernt, die im Text enthalten sind, z. B. HYPERLINK, die Sie gesehen haben. Ihr Code würde:

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); 
} 

Die andere Option ist Apache Tika zu verwenden. Tika bietet Text-Extraktion und Metadaten für eine Vielzahl von Dateien, so dass der gleiche Code auch für .doc, .docx, .pdf und viele andere verwendet werden kann. Um sauber, Klartext Ihres Word-Dokument (Sie können auch XHTML, wenn man lieber), Sie so etwas wie tun würde:

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(); 
+2

Die zweite Lösung nicht in funktionierten meine Tests. TIKA-1.2 hat FORMCHECKBOX und andere Dinge aus DOC-Dateien zurückgegeben. .docx Dateien funktionierten gut. – Simon

+0

Ich würde vorschlagen, dass Sie versuchen, mit der neuesten Tika-Version, 1.3. Wenn das Problem dort immer noch auftritt, bitte [einen Fehler melden] (https://issues.apache.org/jira/browse/TIKA) und lade eine Beispieldatei hoch, die es zeigt, damit wir es untersuchen können! – Gagravarr

+0

Dies geschieht immer noch in Tika 1.3 für mich, für das, was es wert ist. – damd

7

Diese Klasse lesen können sowohl .doc und .docx-Dateien in Java . tika-app-1.2.jar Dazu verwende ich:

/* 
* 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(); 
     } 
    } 
} 

kompilieren:

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

auszuführen:

java -cp ".:tika-app-1.2.jar" TextExtractor SomeWordDocument.doc 
3

die Sie interessieren, funktioniert für mich und ist rein eine POI-Lösung. Sie müssen jedoch nach dem HWPFDocument-Gegenstück suchen. Stellen Sie sicher, dass das Dokument, das Sie lesen, Word 97 vorausgeht, andernfalls verwenden Sie XWPFDocument wie ich.

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 

Nun, wenn Sie bestimmte Teile wollen Sie die getparagraphtext verwenden können, aber nicht den Textextraktor verwenden, verwenden Sie es direkt auf den Absatz wie dieses

for (XWPFParagraph p : adoc.getParagraphs()) 
{ 
    System.out.println(p.getParagraphText()); 
}