Extrahera text från MS Word-dokument i C#

Microsoft Word-dokument används ofta för att skapa och dela textinnehåll. Om du arbetar med Word-dokument i dina C#-program kan du behöva extrahera text från dem. Till exempel för att analysera texten, extrahera vissa delar av ett dokument och kombinera dem till ett enda dokument, och så vidare. I den här bloggen kommer vi att utforska hur man extraherar text från Word-dokument i C#.

C#-bibliotek för att extrahera text från Word-dokument

Aspose.Words for .NET är ett funktionsrikt och lättanvänt bibliotek för att arbeta med Word-dokument. Den erbjuder ett brett utbud av funktioner, inklusive textextraktion, skapande av dokument, manipulation, konvertering och mer. Med Aspose.Words för .NET kan du hantera olika aspekter av Word-dokument, vilket gör det till ett värdefullt verktyg för utvecklare.

Ladda ner DLL:n eller installera biblioteket direkt från NuGet med hjälp av pakethanterarens konsol.

PM> Install-Package Aspose.Words

Extrahera text från Word-dokument

Ett MS Word-dokument består av olika element som inkluderar stycken, tabeller, bilder etc. Därför kan kraven på textextraktion variera från ett scenario till ett annat. Du kan till exempel behöva extrahera text mellan stycken, bokmärken, kommentarer osv.

Varje typ av element i ett Word-dokument representeras som en nod. Därför, för att bearbeta ett dokument, måste du leka med noderna. Så låt oss börja och se hur man extraherar text från Word-dokument i olika scenarier.

Extrahera text från en Word-doc i C#

I det här avsnittet kommer vi att implementera en C#-textextraktor för Word-dokument och arbetsflödet för textextraktion skulle vara som följer:

  • Först kommer vi att definiera de noder som vi vill inkludera i textextraktionsprocessen.
  • Sedan extraherar vi innehållet mellan de angivna noderna (inklusive eller exkluderar start- och slutnoderna).
  • Slutligen kommer vi att använda klonen av extraherade noder, till exempel för att skapa ett nytt Word-dokument som består av extraherat innehåll.

Låt oss nu skriva en metod som heter ExtractContent som vi skickar noderna och några andra parametrar till för att utföra textextraktionen. Denna metod kommer att analysera dokumentet och klona noderna. Följande är parametrarna som vi kommer att skicka till denna metod.

  1. StartNode och EndNode som start- och slutpunkter för utvinningen av innehållet. Dessa kan vara noder på både blocknivå (Paragraph , Table) eller inlinenivå (t.ex. Run, FieldStart, BookmarkStart etc.).
    1. För att skicka ett fält måste du skicka det motsvarande FieldStart-objektet.
    2. För att skicka bokmärken ska noderna BookmarkStart och BookmarkEnd passeras.
    3. För kommentarer ska noderna CommentRangeStart och CommentRangeEnd användas.
  2. IsInclusive definierar om markörerna ingår i extraktionen eller inte. Om det här alternativet är inställt på false och samma nod eller på varandra följande noder skickas, kommer en tom lista att returneras.

Följande är den fullständiga implementeringen av metoden ExtractContent som extraherar innehållet mellan noderna som skickas.

public static ArrayList ExtractContent(Node startNode, Node endNode, bool isInclusive)
{
    // Kontrollera först att noderna som skickas till denna metod är giltiga för användning.
    VerifyParameterNodes(startNode, endNode);

    // Skapa en lista för att lagra de extraherade noderna.
    ArrayList nodes = new ArrayList();

    // Håll ett register över de ursprungliga noderna som skickats till denna metod så att vi kan dela upp markörnoder om det behövs.
    Node originalStartNode = startNode;
    Node originalEndNode = endNode;

    // Extrahera innehåll baserat på noder på blocknivå (stycken och tabeller). Gå igenom föräldranoder för att hitta dem.
    // Vi kommer att dela upp innehållet i första och sista noder beroende på om markörnoderna är inline
    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;
    // Den aktuella noden vi extraherar från dokumentet.
    Node currNode = startNode;

    // Börja extrahera innehåll. Bearbeta alla noder på blocknivå och dela specifikt de första och sista noderna när det behövs så att styckeformateringen behålls.
    // Metoden är lite mer komplex än en vanlig extraherare eftersom vi måste ta hänsyn till att extrahera med inline-noder, fält, bokmärken etc för att göra den riktigt användbar.
    while (isExtracting)
    {
        // Klona den aktuella noden och dess underordnade för att få en kopia.
        Node cloneNode = currNode.Clone(true);
        isEndingNode = currNode.Equals(endNode);

        if ((isStartingNode || isEndingNode) && cloneNode.IsComposite)
        {
            // Vi måste bearbeta varje markör separat så skicka den till en separat metod istället.
            if (isStartingNode)
            {
                ProcessMarker((CompositeNode)cloneNode, nodes, originalStartNode, isInclusive, isStartingNode, isEndingNode);
                isStartingNode = false;
            }

            // Villkor måste vara separata eftersom blocknivåns start- och slutmarkörer kanske är samma nod.
            if (isEndingNode)
            {
                ProcessMarker((CompositeNode)cloneNode, nodes, originalEndNode, isInclusive, isStartingNode, isEndingNode);
                isExtracting = false;
            }
        }
        else
            // Noden är inte en start- eller slutmarkör, lägg bara till kopian i listan.
            nodes.Add(cloneNode);

        // Flytta till nästa nod och extrahera den. Om nästa nod är null betyder det att resten av innehållet finns i ett annat avsnitt.
        if (currNode.NextSibling == null && isExtracting)
        {
            // Flytta till nästa avsnitt.
            Section nextSection = (Section)currNode.GetAncestor(NodeType.Section).NextSibling;
            currNode = nextSection.Body.FirstChild;
        }
        else
        {
            // Flytta till nästa nod i kroppen.
            currNode = currNode.NextSibling;
        }
    }

    // Returnera noderna mellan nodmarkörerna.
    return nodes;
}

Vissa hjälpmetoder krävs också av ExtractContent-metoden för att utföra textextraktionsoperationen, som ges nedan.

public static List<Paragraph> ParagraphsByStyleName(Document doc, string styleName)
{
    // Skapa en array för att samla stycken av den angivna stilen.
    List<Paragraph> paragraphsWithStyle = new List<Paragraph>();

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

    // Titta igenom alla stycken för att hitta de med den angivna stilen.
    foreach (Paragraph paragraph in paragraphs)
    {
        if (paragraph.ParagraphFormat.Style.Name == styleName)
            paragraphsWithStyle.Add(paragraph);
    }

    return paragraphsWithStyle;
}
private static void VerifyParameterNodes(Node startNode, Node endNode)
{
    // Ordningen i vilken dessa kontroller görs är viktig.
    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");

    // Kontrollera att slutnoden ligger efter startnoden i DOM-trädet
    // Kontrollera först om de finns i olika sektioner, sedan om de inte är i kroppen av samma sektion som de befinner sig i.
    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)
{
    // Testa om noden är avstammande från en paragraf- eller tabellnod och inte heller är ett stycke eller en tabell. Ett stycke i en kommentarklass som är härrörande från en paraaf är möjligt.
    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)
{
    // Om vi har att göra med en nod på blocknivå, se bara om den ska inkluderas och lägg till den i listan.
    if (!IsInline(node))
    {
        // Lägg inte till noden två gånger om markörerna är samma nod
        if (!(isStartMarker && isEndMarker))
        {
            if (isInclusive)
                nodes.Add(cloneNode);
        }
        return;
    }

    // Om en markör är en FieldStart-nod kontrollera om den ska inkluderas eller inte.
    // Vi antar för enkelhetens skull att FieldStart och FieldEnd visas i samma stycke.
    if (node.NodeType == NodeType.FieldStart)
    {
        // Om markören är en startnod och inte ingår, hoppa till slutet av fältet.
        // Om markören är en slutnod och den ska inkluderas, flytta till slutfältet så att fältet inte tas bort.
        if ((isStartMarker && !isInclusive) || (!isStartMarker && isInclusive))
        {
            while (node.NextSibling != null && node.NodeType != NodeType.FieldEnd)
                node = node.NextSibling;

        }
    }

    // Om någon av markörerna är en del av en kommentar måste vi flytta pekaren framåt till kommentaren för att inkludera själva kommentaren
    // Nod hittades efter noden CommentRangeEnd.
    if (node.NodeType == NodeType.CommentRangeEnd)
    {
        while (node.NextSibling != null && node.NodeType != NodeType.Comment)
            node = node.NextSibling;

    }

    // Hitta motsvarande nod i vår klonade nod efter index och returnera den.
    // Om start- och slutnoden är desamma kan vissa underordnade noder redan ha tagits bort. Subtrahera
    // Skillnad för att få rätt index.
    int indexDiff = node.ParentNode.ChildNodes.Count - cloneNode.ChildNodes.Count;

    // Antalet barnnoder är identiskt.
    if (indexDiff == 0)
        node = cloneNode.ChildNodes[node.ParentNode.IndexOf(node)];
    else
        node = cloneNode.ChildNodes[node.ParentNode.IndexOf(node) - indexDiff];

    // Ta bort noderna upp till/från markören.
    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();
    }

    // Efter bearbetning kan den sammansatta noden bli tom. Om det har, inkludera det inte.
    if (!(isStartMarker && isEndMarker))
    {
        if (cloneNode.HasChildNodes)
            nodes.Add(cloneNode);
    }

}
public static Document GenerateDocument(Document srcDoc, ArrayList nodes)
{
    // Skapa ett tomt dokument.
    Document dstDoc = new Document();
    // Ta bort första stycket från det tomma dokumentet.
    dstDoc.FirstSection.Body.RemoveAllChildren();

    // Importera varje nod från listan till det nya dokumentet. Behåll nodens ursprungliga formatering.
    NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.KeepSourceFormatting);

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

    // Returnera det genererade dokumentet.
    return dstDoc;
}

Nu är vi redo att använda dessa metoder och extrahera text från ett Word-dokument.

Extrahera text mellan stycken i ett Word-dokument

Låt oss se hur man extraherar innehåll mellan två stycken i ett Word DOCX-dokument. Följande är stegen för att utföra denna operation i C#.

  • Ladda först Word-dokumentet med Document class.
  • Hämta referens till start- och slutstyckena till två objekt med metoden Document.FirstSection.Body.GetChild(NodeType.PARAGRAPH, int, boolean).
  • Anrop ExtractContent(startPara, endPara, True) metod för att extrahera noderna till ett objekt.
  • Anropa hjälpmetoden GenerateDocument(Document, extractedNodes) för att skapa ett dokument som består av det extraherade innehållet.
  • Slutligen sparar du det returnerade dokumentet med metoden Document.Save(sträng).

Följande kodexempel visar hur man extraherar text mellan 7:e och 11:e styckena i ett Word-dokument i C#.

// Ladda Word-dokument
Document doc = new Document("document.docx");

// Samla noderna (GetChild-metoden använder 0-baserat index)
Paragraph startPara = (Paragraph)doc.FirstSection.Body.GetChild(NodeType.Paragraph, 6, true);
Paragraph endPara = (Paragraph)doc.FirstSection.Body.GetChild(NodeType.Paragraph, 10, true);

// Extrahera innehållet mellan dessa noder i dokumentet. Inkludera dessa markörer i extraktionen.
ArrayList extractedNodes = ExtractContent(startPara, endPara, true);

// Infoga innehållet i ett nytt dokument och spara det på disk.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");

Extrahera text mellan olika typer av noder

Du kan även extrahera innehåll mellan olika typer av noder. För demonstration, låt oss extrahera innehåll mellan ett stycke och en tabell och spara det i ett nytt Word-dokument. Följande är stegen för att utföra denna operation.

  • Ladda Word-dokumentet med dokumentklassen.
  • Hämta referens för start- och slutnoderna till två objekt med metoden Document.FirstSection.Body.GetChild(NodeType, int, boolean).
  • Anrop ExtractContent(startPara, endPara, True) metod för att extrahera noderna till ett objekt.
  • Anrop GenerateDocument(Document, extractedNodes) hjälpmetod för att skapa dokument som består av det extraherade innehållet.
  • Spara det returnerade dokumentet med metoden Document.Save(sträng).

Följande kodexempel visar hur man extraherar text mellan ett stycke och en tabell i C#.

// Ladda Word-dokument
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);

// Extrahera innehållet mellan dessa noder i dokumentet. Inkludera dessa markörer i extraktionen.
ArrayList extractedNodes = ExtractContent(startPara, endTable, true);

// Infoga innehållet i ett nytt dokument och spara det på disk.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");

Hämta text mellan stycken baserat på stilar

Låt oss nu kolla in hur man extraherar innehåll mellan stycken baserat på stilar. För demonstration kommer vi att extrahera innehåll mellan den första “Rubrik 1” och den första “Rubrik 3” i Word-dokumentet. Följande steg visar hur man uppnår detta i C#.

  • Ladda först Word-dokumentet med Document class.
  • Extrahera sedan stycken till ett objekt med hjälp av hjälpmetoden ParagraphsByStyleName(Dokument, “Rubrik 1”).
  • Extrahera stycken till ett annat objekt med hjälp av hjälpmetoden ParagraphsByStyleName(Document, “Rubrik 3”).
  • Anropa metoden ExtractContent(startPara, endPara, True) och skicka de första elementen i båda paragrafmatriserna som första och andra parametrar.
  • Anrop GenerateDocument(Document, extractedNodes) hjälpmetod för att skapa dokument som består av det extraherade innehållet.
  • Slutligen sparar du det returnerade dokumentet med metoden Document.Save(sträng).

Följande kodexempel visar hur man extraherar innehåll mellan stycken baserat på stilar.

// Ladda Word-dokument
Document doc = new Document("document.docx");

// Samla en lista över styckena med respektive rubrikstil.
List<Paragraph> parasStyleHeading1 = ParagraphsByStyleName(doc, "Heading 1");
List<Paragraph> parasStyleHeading3 = ParagraphsByStyleName(doc, "Heading 3");

// Använd den första instansen av styckena med dessa formatmallar.
Node startPara1 = (Node)parasStyleHeading1[0];
Node endPara1 = (Node)parasStyleHeading3[0];

// Extrahera innehållet mellan dessa noder i dokumentet. Inkludera inte dessa markörer i extraktionen.
ArrayList extractedNodes = ExtractContent(startPara1, endPara1, false);

// Infoga innehållet i ett nytt dokument och spara det på disk.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");

Läs mer om textextraktion

Du kan utforska andra scenarier för att extrahera text från Word-dokument med hjälp av denna dokumentationsartikeln.

Få gratis Word Text Extractor Library

Du kan få en gratis tillfällig licens för att extrahera text utan utvärderingsbegränsningar.

Slutsats

Aspose.Words för .NET är ett mångsidigt bibliotek som förenklar processen att extrahera text från Word-dokument i C#. Med dess omfattande funktioner och lättanvända API kan du effektivt arbeta med Word-dokument och automatisera olika scenarier för textextraktion. Oavsett om du bygger applikationer som behöver bearbeta Word-dokument eller bara extraherar text, är Aspose.Words för .NET ett värdefullt verktyg för utvecklare.

Du kan utforska andra funktioner i Aspose.Words för .NET med hjälp av dokumentationen. Om du har några frågor är du välkommen att meddela oss via vårt forum.

Se även

Tips: Du kanske vill kontrollera Aspose PowerPoint till Word Converter eftersom den visar den populära konverteringsprocessen för presentation till Word-dokument.