Extrahieren Sie Text aus MS Word Dokumenten in C#

Die Textextraktion aus Word Dokumenten wird häufig in verschiedenen Szenarien durchgeführt. Zum Beispiel, um den Text zu analysieren, bestimmte Abschnitte eines Dokuments zu extrahieren und sie zu einem einzigen Dokument zusammenzufügen und so weiter. In diesem Artikel erfahren Sie, wie Sie Text aus Word Dokumenten programmgesteuert in C# extrahieren. Darüber hinaus werden wir behandeln, wie Inhalte zwischen bestimmten Elementen wie Absätzen, Tabellen usw. dynamisch extrahiert werden.

C# Bibliothek zum Extrahieren von Text aus Word Dokumenten

Aspose.Words for .NET ist eine leistungsstarke Bibliothek, mit der Sie MS Word Dokumente von Grund auf neu erstellen können. Darüber hinaus können Sie die vorhandenen Word Dokumente für Verschlüsselung, Konvertierung, Textextraktion usw. manipulieren. Wir werden diese Bibliothek verwenden, um Text aus den Word DOCX oder DOC Dokumenten zu extrahieren. Sie können die DLL der API herunterladen oder direkt von NuGet mithilfe der Paket-Manager Konsole installieren.

PM> Install-Package Aspose.Words

Textextraktion in Word Dokumenten mit C#

Ein MS Word Dokument besteht aus verschiedenen Elementen, darunter Absätze, Tabellen, Bilder usw. Daher können die Anforderungen an die Textextraktion von Szenario zu Szenario variieren. Beispielsweise müssen Sie möglicherweise Text zwischen Absätzen, Lesezeichen, Kommentaren usw. extrahieren.

Jeder Elementtyp in einem Word Dokument wird als Knoten dargestellt. Um ein Dokument zu verarbeiten, müssen Sie daher mit den Knoten spielen. Lassen Sie uns also beginnen und sehen, wie Sie Text aus Word Dokumenten in verschiedenen Szenarien extrahieren.

Extrahieren Sie Text aus einem Word Dokument in C#

In diesem Abschnitt implementieren wir einen C# Textextraktor für Word Dokumente, und der Arbeitsablauf der Textextraktion würde wie folgt aussehen:

  • Zuerst definieren wir die Knoten, die wir in den Textextraktionsprozess einbeziehen möchten.
  • Dann extrahieren wir den Inhalt zwischen den angegebenen Knoten (einschließlich oder ohne Start und Endknoten).
  • Schließlich verwenden wir den Klon extrahierter Knoten, um zB ein neues Word Dokument zu erstellen, das aus extrahierten Inhalten besteht.

Lassen Sie uns nun eine Methode namens ExtractContent schreiben, an die wir die Knoten und einige andere Parameter übergeben, um die Textextraktion durchzuführen. Diese Methode analysiert das Dokument und klont die Knoten. Im Folgenden sind die Parameter aufgeführt, die wir an diese Methode übergeben.

  1. StartNode und EndNode als Start- bzw. Endpunkt für die Extraktion des Inhalts. Dies können sowohl Knoten auf Blockebene (Absatz , Tabelle) als auch auf Inline-Ebene (z. B. Run, FieldStart, BookmarkStart usw.) sein.
    1. Um ein Feld zu übergeben, sollten Sie das entsprechende FieldStart objekt übergeben.
    2. Um Lesezeichen zu übergeben, sollten die Knoten BookmarkStart und BookmarkEnd übergeben werden.
    3. Für Kommentare sollten die Knoten CommentRangeStart und CommentRangeEnd verwendet werden.
  2. IsInclusive definiert, ob die Marker in der Extraktion enthalten sind oder nicht. Wenn diese Option auf false gesetzt ist und derselbe Knoten oder aufeinanderfolgende Knoten übergeben werden, wird eine leere Liste zurückgegeben.

Das Folgende ist die vollständige Implementierung der ExtractContent methode, die den Inhalt zwischen den übergebenen Knoten extrahiert.

public static ArrayList ExtractContent(Node startNode, Node endNode, bool isInclusive)
{
    // Überprüfen Sie zunächst, ob die an diese Methode übergebenen Knoten für die Verwendung gültig sind.
    VerifyParameterNodes(startNode, endNode);

    // Erstellen Sie eine Liste zum Speichern der extrahierten Knoten.
    ArrayList nodes = new ArrayList();

    // Bewahren Sie eine Aufzeichnung der ursprünglichen Knoten auf, die an diese Methode übergeben wurden, damit wir bei Bedarf Markierungsknoten teilen können.
    Node originalStartNode = startNode;
    Node originalEndNode = endNode;

    // Extrahieren Sie Inhalte basierend auf Knoten auf Blockebene (Absätze und Tabellen). Durchqueren Sie übergeordnete Knoten, um sie zu finden.
    // Wir werden den Inhalt des ersten und letzten Knotens aufteilen, je nachdem, ob die Markierungsknoten inline sind
    while (startNode.ParentNode.NodeType != NodeType.Body)
        startNode = startNode.ParentNode;

    while (endNode.ParentNode.NodeType != NodeType.Body)
        endNode = endNode.ParentNode;

    bool isExtracting = true;
    bool isStartingNode = true;
    bool isEndingNode = false;
    // Der aktuelle Knoten, den wir aus dem Dokument extrahieren.
    Node currNode = startNode;

    // Beginnen Sie mit dem Extrahieren von Inhalten. Verarbeiten Sie alle Knoten auf Blockebene und teilen Sie bei Bedarf gezielt den ersten und den letzten Knoten auf, damit die Absatzformatierung erhalten bleibt.
    // Die Methode ist etwas komplexer als ein normaler Extraktor, da wir die Extraktion mit Inline-Knoten, Feldern, Lesezeichen usw. berücksichtigen müssen, um sie wirklich nützlich zu machen.
    while (isExtracting)
    {
        // Klonen Sie den aktuellen Knoten und seine Kinder, um eine Kopie zu erhalten.
        Node cloneNode = currNode.Clone(true);
        isEndingNode = currNode.Equals(endNode);

        if ((isStartingNode || isEndingNode) && cloneNode.IsComposite)
        {
            // Wir müssen jeden Marker separat verarbeiten, also übergeben Sie ihn stattdessen an eine separate Methode.
            if (isStartingNode)
            {
                ProcessMarker((CompositeNode)cloneNode, nodes, originalStartNode, isInclusive, isStartingNode, isEndingNode);
                isStartingNode = false;
            }

            // Die Bedingung muss getrennt sein, da die Start und Endmarkierungen auf Blockebene möglicherweise derselbe Knoten sind.
            if (isEndingNode)
            {
                ProcessMarker((CompositeNode)cloneNode, nodes, originalEndNode, isInclusive, isStartingNode, isEndingNode);
                isExtracting = false;
            }
        }
        else
            // Knoten ist keine Start oder Endmarkierung, fügen Sie einfach die Kopie zur Liste hinzu.
            nodes.Add(cloneNode);

        // Gehen Sie zum nächsten Knoten und extrahieren Sie ihn. Wenn der nächste Knoten null ist, bedeutet dies, dass der Rest des Inhalts in einem anderen Abschnitt gefunden wird.
        if (currNode.NextSibling == null && isExtracting)
        {
            // Wechseln Sie zum nächsten Abschnitt.
            Section nextSection = (Section)currNode.GetAncestor(NodeType.Section).NextSibling;
            currNode = nextSection.Body.FirstChild;
        }
        else
        {
            // Wechseln Sie zum nächsten Knoten im Körper.
            currNode = currNode.NextSibling;
        }
    }

    // Geben Sie die Knoten zwischen den Knotenmarkierungen zurück.
    return nodes;
}

Einige Hilfsmethoden werden auch von der ExtractContent methode benötigt, um die Textextraktionsoperation durchzuführen, die unten angegeben ist.

public static List<Paragraph> ParagraphsByStyleName(Document doc, string styleName)
{
    // Erstellen Sie ein Array, um Absätze des angegebenen Stils zu sammeln.
    List<Paragraph> paragraphsWithStyle = new List<Paragraph>();

    NodeCollection paragraphs = doc.GetChildNodes(NodeType.Paragraph, true);

    // Durchsuchen Sie alle Absätze, um diejenigen mit dem angegebenen Stil zu finden.
    foreach (Paragraph paragraph in paragraphs)
    {
        if (paragraph.ParagraphFormat.Style.Name == styleName)
            paragraphsWithStyle.Add(paragraph);
    }

    return paragraphsWithStyle;
}
private static void VerifyParameterNodes(Node startNode, Node endNode)
{
    // Die Reihenfolge, in der diese Überprüfungen durchgeführt werden, ist wichtig.
    if (startNode == null)
        throw new ArgumentException("Start node cannot be null");
    if (endNode == null)
        throw new ArgumentException("End node cannot be null");

    if (!startNode.Document.Equals(endNode.Document))
        throw new ArgumentException("Start node and end node must belong to the same document");

    if (startNode.GetAncestor(NodeType.Body) == null || endNode.GetAncestor(NodeType.Body) == null)
        throw new ArgumentException("Start node and end node must be a child or descendant of a body");

    // Überprüfen Sie, ob der Endknoten nach dem Startknoten im DOM-Baum liegt
    // Überprüfen Sie zuerst, ob sie sich in verschiedenen Abschnitten befinden, und überprüfen Sie dann ihre Position im Hauptteil des gleichen Abschnitts, in dem sie sich befinden.
    Section startSection = (Section)startNode.GetAncestor(NodeType.Section);
    Section endSection = (Section)endNode.GetAncestor(NodeType.Section);

    int startIndex = startSection.ParentNode.IndexOf(startSection);
    int endIndex = endSection.ParentNode.IndexOf(endSection);

    if (startIndex == endIndex)
    {
        if (startSection.Body.IndexOf(startNode) > endSection.Body.IndexOf(endNode))
            throw new ArgumentException("The end node must be after the start node in the body");
    }
    else if (startIndex > endIndex)
        throw new ArgumentException("The section of end node must be after the section start node");
}
private static bool IsInline(Node node)
{
    // Testen Sie, ob der Knoten Nachkomme eines Absatz oder Tabellenknotens ist und auch kein Absatz oder eine Tabelle ist. Ein Absatz innerhalb einer Kommentarklasse, die von einem Absatz abstammt, ist möglich.
    return ((node.GetAncestor(NodeType.Paragraph) != null || node.GetAncestor(NodeType.Table) != null) && !(node.NodeType == NodeType.Paragraph || node.NodeType == NodeType.Table));
}
private static void ProcessMarker(CompositeNode cloneNode, ArrayList nodes, Node node, bool isInclusive, bool isStartMarker, bool isEndMarker)
{
    // Wenn es sich um einen Knoten auf Blockebene handelt, prüfen Sie einfach, ob er enthalten sein soll, und fügen Sie ihn der Liste hinzu.
    if (!IsInline(node))
    {
        // Fügen Sie den Knoten nicht zweimal hinzu, wenn die Markierungen derselbe Knoten sind
        if (!(isStartMarker && isEndMarker))
        {
            if (isInclusive)
                nodes.Add(cloneNode);
        }
        return;
    }

    // Wenn ein Marker ein FieldStart-Knoten ist, prüfen Sie, ob er eingeschlossen werden soll oder nicht.
    // Wir gehen der Einfachheit halber davon aus, dass FieldStart und FieldEnd im selben Absatz erscheinen.
    if (node.NodeType == NodeType.FieldStart)
    {
        // Wenn die Markierung ein Startknoten ist und nicht eingeschlossen wird, dann springe zum Ende des Felds.
        // Wenn die Markierung ein Endknoten ist und eingeschlossen werden soll, bewegen Sie sich zum Endfeld, damit das Feld nicht entfernt wird.
        if ((isStartMarker && !isInclusive) || (!isStartMarker && isInclusive))
        {
            while (node.NextSibling != null && node.NodeType != NodeType.FieldEnd)
                node = node.NextSibling;

        }
    }

    // Wenn eine der Markierungen Teil eines Kommentars ist, müssen wir, um den Kommentar selbst einzuschließen, den Mauszeiger nach vorne zum Kommentar bewegen
    // Knoten, der nach dem CommentRangeEnd-Knoten gefunden wurde.
    if (node.NodeType == NodeType.CommentRangeEnd)
    {
        while (node.NextSibling != null && node.NodeType != NodeType.Comment)
            node = node.NextSibling;

    }

    // Suchen Sie den entsprechenden Knoten in unserem geklonten Knoten nach Index und geben Sie ihn zurück.
    // Wenn Start und Endknoten identisch sind, wurden möglicherweise bereits einige untergeordnete Knoten entfernt. Subtrahieren Sie die
    // Unterschied, um den richtigen Index zu erhalten.
    int indexDiff = node.ParentNode.ChildNodes.Count - cloneNode.ChildNodes.Count;

    // Anzahl untergeordneter Knoten identisch.
    if (indexDiff == 0)
        node = cloneNode.ChildNodes[node.ParentNode.IndexOf(node)];
    else
        node = cloneNode.ChildNodes[node.ParentNode.IndexOf(node) - indexDiff];

    // Entfernen Sie die Knoten bis zum/vom Marker.
    bool isSkip = false;
    bool isProcessing = true;
    bool isRemoving = isStartMarker;
    Node nextNode = cloneNode.FirstChild;

    while (isProcessing && nextNode != null)
    {
        Node currentNode = nextNode;
        isSkip = false;

        if (currentNode.Equals(node))
        {
            if (isStartMarker)
            {
                isProcessing = false;
                if (isInclusive)
                    isRemoving = false;
            }
            else
            {
                isRemoving = true;
                if (isInclusive)
                    isSkip = true;
            }
        }

        nextNode = nextNode.NextSibling;
        if (isRemoving && !isSkip)
            currentNode.Remove();
    }

    // Nach der Verarbeitung kann der zusammengesetzte Knoten leer werden. Wenn ja, schließen Sie es nicht ein.
    if (!(isStartMarker && isEndMarker))
    {
        if (cloneNode.HasChildNodes)
            nodes.Add(cloneNode);
    }

}
public static Document GenerateDocument(Document srcDoc, ArrayList nodes)
{
    // Erstellen Sie ein leeres Dokument.
    Document dstDoc = new Document();
    // Entfernen Sie den ersten Absatz aus dem leeren Dokument.
    dstDoc.FirstSection.Body.RemoveAllChildren();

    // Importieren Sie jeden Knoten aus der Liste in das neue Dokument. Behalten Sie die ursprüngliche Formatierung des Knotens bei.
    NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.KeepSourceFormatting);

    foreach (Node node in nodes)
    {
        Node importNode = importer.ImportNode(node, true);
        dstDoc.FirstSection.Body.AppendChild(importNode);
    }

    // Geben Sie das generierte Dokument zurück.
    return dstDoc;
}

Jetzt sind wir bereit, diese Methoden zu nutzen und Text aus einem Word Dokument zu extrahieren.

Extrahieren Sie Text zwischen Absätzen in einem Word Dokument

Sehen wir uns an, wie man Inhalte zwischen zwei Absätzen in einem Word-DOCX-Dokument extrahiert. Im Folgenden sind die Schritte zum Ausführen dieses Vorgangs in C# aufgeführt.

  • Laden Sie zuerst das Word Dokument mit der Document Klasse.
  • Rufen Sie mithilfe der Methode Document.FirstSection.Body.GetChild(NodeType.PARAGRAPH, int, boolean) den Verweis auf den Anfangs und Endabsatz in zwei Objekte ab.
  • Rufen Sie die Methode ExtractContent(startPara, endPara, True) auf, um die Knoten in ein Objekt zu extrahieren.
  • Rufen Sie die GenerateDocument(Document, extractedNodes)-Hilfsmethode auf, um ein Dokument zu erstellen, das aus dem extrahierten Inhalt besteht.
  • Speichern Sie schließlich das zurückgegebene Dokument mit der methode Document.Save(string).

Das folgende Codebeispiel zeigt, wie Text zwischen dem 7. und 11. Absatz in einem Word Dokument in C# extrahiert wird.

// Word Dokument laden
Document doc = new Document("document.docx");

// Sammeln Sie die Knoten (die GetChild methode verwendet einen 0-basierten Index)
Paragraph startPara = (Paragraph)doc.FirstSection.Body.GetChild(NodeType.Paragraph, 6, true);
Paragraph endPara = (Paragraph)doc.FirstSection.Body.GetChild(NodeType.Paragraph, 10, true);

// Extrahieren Sie den Inhalt zwischen diesen Knoten im Dokument. Schließen Sie diese Markierungen in die Extraktion ein.
ArrayList extractedNodes = ExtractContent(startPara, endPara, true);

// Fügen Sie den Inhalt in ein neues Dokument ein und speichern Sie es auf der Festplatte.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");

Extrahieren Sie Text zwischen verschiedenen Arten von Knoten in einem Word Dokument

Sie können auch Inhalte zwischen verschiedenen Arten von Knoten extrahieren. Lassen Sie uns zur Demonstration den Inhalt zwischen einem Absatz und einer Tabelle extrahieren und in einem neuen Word Dokument speichern. Im Folgenden sind die Schritte zum Ausführen dieses Vorgangs aufgeführt.

  • Laden Sie das Word Dokument mithilfe der Document Klasse.
  • Rufen Sie mithilfe der Methode Document.FirstSection.Body.GetChild(NodeType, int, boolean) die Referenz der Start und Endknoten in zwei Objekte ab.
  • Rufen Sie die Methode ExtractContent(startPara, endPara, True) auf, um die Knoten in ein Objekt zu extrahieren.
  • Rufen Sie die GenerateDocument(Document, extractedNodes)-Hilfsmethode auf, um ein Dokument zu erstellen, das aus dem extrahierten Inhalt besteht.
  • Speichern Sie das zurückgegebene Dokument mit der Document.Save(string) methode.

Das folgende Codebeispiel zeigt, wie Text zwischen einem Absatz und einer Tabelle in C# extrahiert wird.

// Word Dokument laden
Document doc = new Document("document.docx");

Paragraph startPara = (Paragraph)doc.LastSection.GetChild(NodeType.Paragraph, 2, true);
Table endTable = (Table)doc.LastSection.GetChild(NodeType.Table, 0, true);

// Extrahieren Sie den Inhalt zwischen diesen Knoten im Dokument. Schließen Sie diese Markierungen in die Extraktion ein.
ArrayList extractedNodes = ExtractContent(startPara, endTable, true);

// Fügen Sie den Inhalt in ein neues Dokument ein und speichern Sie es auf der Festplatte.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");

Extrahieren Sie Text zwischen Absätzen basierend auf Stilen

Schauen wir uns nun an, wie Sie Inhalte zwischen Absätzen basierend auf Stilen extrahieren. Zur Demonstration extrahieren wir den Inhalt zwischen der ersten „Überschrift 1“ und der ersten „Überschrift 3“ im Word Dokument. Die folgenden Schritte zeigen, wie Sie dies in C# erreichen.

  • Laden Sie zuerst das Word Dokument mit der Document Klasse.
  • Extrahieren Sie dann mithilfe der Hilfsmethode ParagraphsByStyleName(Document, “Heading 1”) Absätze in ein Objekt.
  • Extrahieren Sie Absätze mithilfe der Hilfsmethode ParagraphsByStyleName(Document, “Heading 3”) in ein anderes Objekt.
  • Rufen Sie die Methode ExtractContent(startPara, endPara, True) auf und übergeben Sie die ersten Elemente in beiden Absatzarrays als ersten und zweiten Parameter.
  • Rufen Sie die GenerateDocument(Document, extractedNodes)-Hilfsmethode auf, um ein Dokument zu erstellen, das aus dem extrahierten Inhalt besteht.
  • Speichern Sie schließlich das zurückgegebene Dokument mit der methode Document.Save(string).

Das folgende Codebeispiel zeigt, wie Inhalte zwischen Absätzen basierend auf Stilen extrahiert werden.

// Word Dokument laden
Document doc = new Document("document.docx");

// Sammeln Sie eine Liste der Absätze mit den entsprechenden Überschriftenstilen.
List<Paragraph> parasStyleHeading1 = ParagraphsByStyleName(doc, "Heading 1");
List<Paragraph> parasStyleHeading3 = ParagraphsByStyleName(doc, "Heading 3");

// Verwenden Sie die erste Instanz der Absätze mit diesen Stilen.
Node startPara1 = (Node)parasStyleHeading1[0];
Node endPara1 = (Node)parasStyleHeading3[0];

// Extrahieren Sie den Inhalt zwischen diesen Knoten im Dokument. Schließen Sie diese Markierungen nicht in die Extraktion ein.
ArrayList extractedNodes = ExtractContent(startPara1, endPara1, false);

// Fügen Sie den Inhalt in ein neues Dokument ein und speichern Sie es auf der Festplatte.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");

Weiterlesen

In diesem Dokumentation artikel können Sie andere Szenarien zum Extrahieren von Text aus Word Dokumenten erkunden.

Holen Sie sich eine kostenlose API Lizenz

Sie können eine vorübergehende Lizenz erwerben, um Aspose.Words for .NET ohne Evaluierungseinschränkungen zu verwenden.

Fazit

In diesem Artikel haben Sie gelernt, wie Sie mit C# Text aus MS Word Dokumenten extrahieren. Darüber hinaus haben Sie gesehen, wie Inhalte zwischen ähnlichen oder unterschiedlichen Knotentypen in einem Word Dokument programmgesteuert extrahiert werden. So können Sie Ihren eigenen MS Word-Textextraktor in C# erstellen. Außerdem können Sie weitere Funktionen von Aspose.Words for .NET mithilfe der Dokumentation erkunden. Falls Sie Fragen haben, können Sie uns diese gerne über unser Forum mitteilen.

Siehe auch

Tipp: Sie sollten sich Aspose PowerPoint to Word Converter ansehen, da es den beliebten Umwandlungsprozess von Präsentationen in Word Dokumente demonstriert.