Extrahujte text z dokumentů MS Word v C#

Extrakce textu z dokumentů aplikace Word se často provádí v různých scénářích. Například analyzovat text, extrahovat určité části dokumentu a spojit je do jednoho dokumentu a tak dále. V tomto článku se dozvíte, jak extrahovat text z dokumentů Wordu v C#. Kromě toho se budeme zabývat tím, jak extrahovat obsah mezi konkrétními prvky dokumentu aplikace Word, jako jsou odstavce, tabulky atd.

Jak extrahovat text z Wordu v C#

Pro extrahování textu z dokumentů aplikace Word použijeme Aspose.Words for .NET. Je to výkonná knihovna, která umožňuje vytvářet a zpracovávat dokumenty MS Word. Můžete snadno získat jeho bezplatnou licenci a extrahovat text z dokumentů aplikace Word bez jakýchkoli omezení.

Stáhněte si DLL nebo nainstalujte knihovnu přímo z NuGet pomocí konzole správce balíčků.

PM> Install-Package Aspose.Words

Extrahování textu z dokumentů aplikace Word

Dokument MS Word se skládá z různých prvků, které zahrnují odstavce, tabulky, obrázky atd. Proto se požadavky na extrakci textu mohou v jednotlivých scénářích lišit. Můžete například potřebovat extrahovat text mezi odstavci, záložkami, komentáři atd.

Každý typ prvku v dokumentu aplikace Word je reprezentován jako uzel. Pro zpracování dokumentu si tedy budete muset pohrát s uzly. Začněme a podívejme se, jak extrahovat text z dokumentů aplikace Word v různých scénářích.

Získejte text z Word DOCX v C#

V této části se chystáme implementovat extraktor textu C# pro dokumenty Word a pracovní postup extrakce textu by byl následující:

  • Nejprve definujeme uzly, které chceme zahrnout do procesu extrakce textu.
  • Potom extrahujeme obsah mezi zadanými uzly (včetně nebo vyloučení počátečního a koncového uzlu).
  • Nakonec použijeme klon extrahovaných uzlů, např. k vytvoření nového dokumentu Word sestávajícího z extrahovaného obsahu.

Pojďme si nyní napsat metodu s názvem ExtractContent, které předáme uzly a některé další parametry pro provedení extrakce textu. Tato metoda analyzuje dokument a klonuje uzly. Následují parametry, které této metodě předáme.

  1. StartNode a EndNode jako počáteční a koncové body pro extrakci obsahu. Mohou to být uzly na úrovni bloku (Paragraph , Table) nebo inline (např. Run, FieldStart, BookmarkStart atd.).
    1. Chcete-li předat pole, měli byste předat odpovídající objekt FieldStart.
    2. Pro předání záložek by měly být předány uzly BookmarkStart a BookmarkEnd.
    3. Pro komentáře by měly být použity uzly CommentRangeStart a CommentRangeEnd.
  2. IsInclusive definuje, zda jsou značky zahrnuty do extrakce nebo ne. Pokud je tato možnost nastavena na hodnotu false a je předán stejný uzel nebo po sobě jdoucí uzly, bude vrácen prázdný seznam.

Následuje kompletní implementace metody ExtractContent, která extrahuje obsah mezi uzly, které jsou předány.

public static ArrayList ExtractContent(Node startNode, Node endNode, bool isInclusive)
{
    // Nejprve zkontrolujte, zda jsou uzly předané této metodě platné pro použití.
    VerifyParameterNodes(startNode, endNode);

    // Vytvořte seznam pro uložení extrahovaných uzlů.
    ArrayList nodes = new ArrayList();

    // Zaznamenejte si původní uzly předané této metodě, abychom mohli v případě potřeby rozdělit značkovací uzly.
    Node originalStartNode = startNode;
    Node originalEndNode = endNode;

    // Extrahujte obsah na základě uzlů na úrovni bloku (odstavců a tabulek). Procházejte nadřazené uzly a najděte je.
    // Obsah prvního a posledního uzlu rozdělíme podle toho, zda jsou uzly značky vložené
    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;
    // Aktuální uzel, který extrahujeme z dokumentu.
    Node currNode = startNode;

    // Začněte extrahovat obsah. Zpracujte všechny uzly na úrovni bloku a v případě potřeby konkrétně rozdělte první a poslední uzel, aby bylo zachováno formátování odstavce.
    // Metoda je o něco složitější než běžný extraktor, protože musíme zohlednit extrakci pomocí vložených uzlů, polí, záložek atd., aby byla opravdu užitečná.
    while (isExtracting)
    {
        // Naklonujte aktuální uzel a jeho potomky, abyste získali kopii.
        Node cloneNode = currNode.Clone(true);
        isEndingNode = currNode.Equals(endNode);

        if ((isStartingNode || isEndingNode) && cloneNode.IsComposite)
        {
            // Potřebujeme zpracovat každou značku zvlášť, takže ji místo toho předáme samostatné metodě.
            if (isStartingNode)
            {
                ProcessMarker((CompositeNode)cloneNode, nodes, originalStartNode, isInclusive, isStartingNode, isEndingNode);
                isStartingNode = false;
            }

            // Podmíněné musí být oddělené, protože značky začátku a konce úrovně bloku mohou být stejný uzel.
            if (isEndingNode)
            {
                ProcessMarker((CompositeNode)cloneNode, nodes, originalEndNode, isInclusive, isStartingNode, isEndingNode);
                isExtracting = false;
            }
        }
        else
            // Uzel není značka začátku nebo konce, jednoduše přidejte kopii do seznamu.
            nodes.Add(cloneNode);

        // Přesuňte se na další uzel a extrahujte jej. Pokud je další uzel null, znamená to, že zbytek obsahu se nachází v jiné sekci.
        if (currNode.NextSibling == null && isExtracting)
        {
            // Přejít na další sekci.
            Section nextSection = (Section)currNode.GetAncestor(NodeType.Section).NextSibling;
            currNode = nextSection.Body.FirstChild;
        }
        else
        {
            // Přesuňte se na další uzel v těle.
            currNode = currNode.NextSibling;
        }
    }

    // Vraťte uzly mezi značky uzlů.
    return nodes;
}

Některé pomocné metody jsou také vyžadovány metodou ExtractContent k provedení operace extrakce textu, které jsou uvedeny níže.

public static List<Paragraph> ParagraphsByStyleName(Document doc, string styleName)
{
    // Vytvořte pole pro shromažďování odstavců zadaného stylu.
    List<Paragraph> paragraphsWithStyle = new List<Paragraph>();

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

    // Prohlédněte si všechny odstavce a najděte ty se zadaným stylem.
    foreach (Paragraph paragraph in paragraphs)
    {
        if (paragraph.ParagraphFormat.Style.Name == styleName)
            paragraphsWithStyle.Add(paragraph);
    }

    return paragraphsWithStyle;
}
private static void VerifyParameterNodes(Node startNode, Node endNode)
{
    // Důležité je pořadí, ve kterém se tyto kontroly provádějí.
    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");

    // Zkontrolujte, že koncový uzel je za počátečním uzlem ve stromu DOM
    // Nejprve zkontrolujte, zda jsou v různých sekcích, a pak, zda nejsou, zkontrolujte jejich polohu v těle stejné sekce, ve které se nacházejí.
    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)
{
    // Otestujte, zda je uzel následovníkem uzlu Odstavec nebo Tabulka a také není odstavcem nebo tabulkou. Je možný odstavec uvnitř třídy komentáře, která je potomkem pararafu.
    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)
{
    // Pokud se zabýváme uzlem na úrovni bloku, podívejte se, zda by měl být zahrnut, a přidejte jej do seznamu.
    if (!IsInline(node))
    {
        // Nepřidávejte uzel dvakrát, pokud jsou značky stejný uzel
        if (!(isStartMarker && isEndMarker))
        {
            if (isInclusive)
                nodes.Add(cloneNode);
        }
        return;
    }

    // Pokud je značka uzel FieldStart, zkontrolujte, zda má být zahrnuta nebo ne.
    // Pro jednoduchost předpokládáme, že FieldStart a FieldEnd se objeví ve stejném odstavci.
    if (node.NodeType == NodeType.FieldStart)
    {
        // Pokud je značka počátečním uzlem a není zahrnuta, přejděte na konec pole.
        // Pokud je značka koncovým uzlem a má být zahrnuta, přesuňte se na koncové pole, aby pole nebylo odstraněno.
        if ((isStartMarker && !isInclusive) || (!isStartMarker && isInclusive))
        {
            while (node.NextSibling != null && node.NodeType != NodeType.FieldEnd)
                node = node.NextSibling;

        }
    }

    // Pokud je kterákoli značka součástí komentáře, pak k zahrnutí samotného komentáře musíme posunout ukazatel dopředu na komentář
    // Uzel nalezen za uzlem CommentRangeEnd.
    if (node.NodeType == NodeType.CommentRangeEnd)
    {
        while (node.NextSibling != null && node.NodeType != NodeType.Comment)
            node = node.NextSibling;

    }

    // Najděte odpovídající uzel v našem klonovaném uzlu podle indexu a vraťte jej.
    // Pokud jsou počáteční a koncový uzel stejné, některé podřízené uzly již mohly být odstraněny. Odečtěte
    // Rozdíl pro získání správného indexu.
    int indexDiff = node.ParentNode.ChildNodes.Count - cloneNode.ChildNodes.Count;

    // Počet podřízených uzlů je stejný.
    if (indexDiff == 0)
        node = cloneNode.ChildNodes[node.ParentNode.IndexOf(node)];
    else
        node = cloneNode.ChildNodes[node.ParentNode.IndexOf(node) - indexDiff];

    // Odstraňte uzly až k/od značky.
    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();
    }

    // Po zpracování se může složený uzel vyprázdnit. Pokud má, nezahrnujte jej.
    if (!(isStartMarker && isEndMarker))
    {
        if (cloneNode.HasChildNodes)
            nodes.Add(cloneNode);
    }

}
public static Document GenerateDocument(Document srcDoc, ArrayList nodes)
{
    // Vytvořte prázdný dokument.
    Document dstDoc = new Document();
    // Odeberte první odstavec z prázdného dokumentu.
    dstDoc.FirstSection.Body.RemoveAllChildren();

    // Importujte každý uzel ze seznamu do nového dokumentu. Zachovejte původní formátování uzlu.
    NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.KeepSourceFormatting);

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

    // Vraťte vygenerovaný dokument.
    return dstDoc;
}

Nyní jsme připraveni použít tyto metody a extrahovat text z dokumentu aplikace Word.

Extrahujte text mezi odstavci v dokumentu aplikace Word

Podívejme se, jak extrahovat obsah mezi dvěma odstavci v dokumentu Word DOCX. Následují kroky k provedení této operace v C#.

  • Nejprve načtěte dokument aplikace Word pomocí třídy Document.
  • Získejte odkaz na počáteční a koncový odstavce do dvou objektů pomocí metody Document.FirstSection.Body.GetChild(NodeType.PARAGRAPH, int, boolean).
  • Voláním metody ExtractContent(startPara, endPara, True) extrahujte uzly do objektu.
  • Zavolejte pomocnou metodu GenerateDocument(Document, extractNodes) a vytvořte dokument skládající se z extrahovaného obsahu.
  • Nakonec uložte vrácený dokument pomocí metody Document.Save(string).

Následující ukázka kódu ukazuje, jak extrahovat text mezi 7. a 11. odstavcem v dokumentu aplikace Word v jazyce C#.

// Načíst dokument aplikace Word
Document doc = new Document("document.docx");

// Shromážděte uzly (metoda GetChild používá index založený na 0)
Paragraph startPara = (Paragraph)doc.FirstSection.Body.GetChild(NodeType.Paragraph, 6, true);
Paragraph endPara = (Paragraph)doc.FirstSection.Body.GetChild(NodeType.Paragraph, 10, true);

// Extrahujte obsah mezi těmito uzly v dokumentu. Zahrňte tyto značky do extrakce.
ArrayList extractedNodes = ExtractContent(startPara, endPara, true);

// Vložte obsah do nového dokumentu a uložte jej na disk.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");

Extrahujte text mezi různými typy uzlů v dokumentu aplikace Word

Můžete také extrahovat obsah mezi různými typy uzlů. Pro demonstraci vyjmeme obsah mezi odstavcem a tabulkou a uložíme jej do nového dokumentu aplikace Word. Následují kroky k provedení této operace.

  • Načtěte dokument aplikace Word pomocí třídy Document.
  • Získejte odkaz na počáteční a koncový uzel do dvou objektů pomocí metody Document.FirstSection.Body.GetChild(NodeType, int, boolean).
  • Voláním metody ExtractContent(startPara, endPara, True) extrahujte uzly do objektu.
  • Zavolejte pomocnou metodu GenerateDocument (Document, extractNodes) k vytvoření dokumentu sestávajícího z extrahovaného obsahu.
  • Uložte vrácený dokument pomocí metody Document.Save(string).

Následující ukázka kódu ukazuje, jak extrahovat text mezi odstavcem a tabulkou v C#.

// Načíst dokument aplikace Word
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);

// Extrahujte obsah mezi těmito uzly v dokumentu. Zahrňte tyto značky do extrakce.
ArrayList extractedNodes = ExtractContent(startPara, endTable, true);

// Vložte obsah do nového dokumentu a uložte jej na disk.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");

Získejte text mezi odstavci na základě stylů

Pojďme se nyní podívat, jak extrahovat obsah mezi odstavci na základě stylů. Pro demonstraci se chystáme extrahovat obsah mezi prvním „Nadpisem 1“ a prvním „Nadpisem 3“ v dokumentu Word. Následující kroky ukazují, jak toho dosáhnout v C#.

  • Nejprve načtěte dokument aplikace Word pomocí třídy Document.
  • Potom extrahujte odstavce do objektu pomocí pomocné metody SectionsByStyleName(Document, “Nadpis 1”).
  • Extrahujte odstavce do jiného objektu pomocí pomocné metody CharactersByStyleName(Document, “Nadpis 3”).
  • Zavolejte metodu ExtractContent(startPara, endPara, True) a předejte první prvky v obou polích odstavců jako první a druhý parametr.
  • Zavolejte pomocnou metodu GenerateDocument (Document, extractNodes) k vytvoření dokumentu sestávajícího z extrahovaného obsahu.
  • Nakonec uložte vrácený dokument pomocí metody Document.Save(string).

Následující ukázka kódu ukazuje, jak extrahovat obsah mezi odstavci na základě stylů.

// Načíst dokument aplikace Word
Document doc = new Document("document.docx");

// Shromážděte seznam odstavců pomocí příslušných stylů nadpisů.
List<Paragraph> parasStyleHeading1 = ParagraphsByStyleName(doc, "Heading 1");
List<Paragraph> parasStyleHeading3 = ParagraphsByStyleName(doc, "Heading 3");

// Použijte první výskyt odstavců s těmito styly.
Node startPara1 = (Node)parasStyleHeading1[0];
Node endPara1 = (Node)parasStyleHeading3[0];

// Extrahujte obsah mezi těmito uzly v dokumentu. Nezahrnujte tyto značky do extrakce.
ArrayList extractedNodes = ExtractContent(startPara1, endPara1, false);

// Vložte obsah do nového dokumentu a uložte jej na disk.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");

Přečtěte si více o extrakci textu

Další scénáře extrahování textu z dokumentů aplikace Word můžete prozkoumat pomocí tohoto článku dokumentace.

Zdarma MS Word Text Extractor

Můžete získat bezplatnou dočasnou licenci k extrahování textu bez omezení hodnocení.

Závěr

V tomto článku jste se naučili extrahovat text z dokumentů MS Word pomocí C#. Navíc jste viděli, jak programově extrahovat obsah mezi podobnými nebo různými typy uzlů v dokumentu aplikace Word. Můžete si tak vytvořit svůj vlastní textový extraktor MS Word v C#. Kromě toho můžete prozkoumat další funkce Aspose.Words for .NET pomocí dokumentace. V případě jakýchkoli dotazů nás neváhejte kontaktovat prostřednictvím našeho fóra.

Viz také

Tip: Možná budete chtít zaškrtnout převaděč Aspose PowerPoint to Word, protože ukazuje oblíbený proces převodu dokumentů z prezentace do Wordu.