如何在 C# 中从 MS Office 文档中提取文本

Posted

技术标签:

【中文标题】如何在 C# 中从 MS Office 文档中提取文本【英文标题】:How to extract text from MS office documents in C# 【发布时间】:2010-11-03 22:01:41 【问题描述】:

我试图使用 C# 从 MS Word(.doc、.docx)、Excel 和 Powerpoint 中提取文本(字符串)。我在哪里可以找到一个免费且简单的 .Net 库来阅读 MS Office 文档? 我尝试使用 NPOI,但没有获得有关如何使用 NPOI 的示例。

【问题讨论】:

【参考方案1】:

对于 Microsoft Word 2007 和 Microsoft Word 2010 (.docx) 文件,您可以使用 Open XML SDK。这个 sn-p 代码将打开一个文档并将其内容作为文本返回。对于任何试图使用正则表达式来解析 Word 文档内容的人来说,它尤其有用。要使用此解决方案,您需要参考 DocumentFormat.OpenXml.dll,它是 OpenXML SDK 的一部分。

见:http://msdn.microsoft.com/en-us/library/bb448854.aspx

 public static string TextFromWord(SPFile file)
    
        const string wordmlNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";

        StringBuilder textBuilder = new StringBuilder();
        using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(file.OpenBinaryStream(), false))
        
            // Manage namespaces to perform XPath queries.  
            NameTable nt = new NameTable();
            XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
            nsManager.AddNamespace("w", wordmlNamespace);

            // Get the document part from the package.  
            // Load the XML in the document part into an XmlDocument instance.  
            XmlDocument xdoc = new XmlDocument(nt);
            xdoc.Load(wdDoc.MainDocumentPart.GetStream());

            XmlNodeList paragraphNodes = xdoc.SelectNodes("//w:p", nsManager);
            foreach (XmlNode paragraphNode in paragraphNodes)
            
                XmlNodeList textNodes = paragraphNode.SelectNodes(".//w:t", nsManager);
                foreach (System.Xml.XmlNode textNode in textNodes)
                
                    textBuilder.Append(textNode.InnerText);
                
                textBuilder.Append(Environment.NewLine);
            

        
        return textBuilder.ToString();
    

【讨论】:

@adrianbanks 我觉得这个答案目前比接受的答案更好,因为接受的答案在某些版本的 Windows 上不起作用,而且 IFilter 是一个已弃用的接口。当然,在撰写阿德里安的帖子时,情况并非如此。 SPFile 怎么样?您在函数中输入的参数就是这种类型,我能找到的只是 Microsoft.Sharepoint.dll -> 中的 Microsoft.Sharepoint 命名空间,而且这个 dll 不容易找到。你参考了什么来获取 SPFile? @user867703 您不必使用 SPFile。这是一个例子。您可以使用任何 .docx 文件(以二进制流形式打开)。看看 WordprocessingDocument.Open 方法,这是重要的方法。 我只是将 SPFile 更改为路径(字符串),并且在 open 方法中我只使用了路径 -> 它可以工作。解决方案非常清晰和简单。 @KyleM 这看起来不像在 64 位系统上为我工作。我找不到 64 位系统的 DocumentFormat.OpenXML dll。添加32位不起作用。还是我做错了什么?【参考方案2】:

使用 PInvokes,您可以使用IFilter 接口(在 Windows 上)。许多常见文件类型的 IFilter 随 Windows 一起安装(您可以使用 this 工具浏览它们。您可以只要求 IFilter 从文件中返回文本。有几组示例代码(here 是其中之一)这样的例子)。

【讨论】:

有趣...一个非常偷偷摸摸的解决方案:) 并非如此。这是 Windows 上的索引服务使用的机制,我认为桌面搜索也使用它。我用它来索引 pdf(通过安装 Adob​​e IFilter - adobe.com/support/downloads/detail.jsp?ftpID=2611)、所有类型的 Office 文档(这些 IFilter 随 Windows 一起安装)和其他几种文件类型。当它工作时,它工作得很好。但有时,您不会从 IFilter 收到任何文本,也没有理由说明原因。 我使用了 pInvoke,发现它非常棒。要从任何文档中提取文本,我们所要做的就是确保在机器上安装了适当的 IFilter(或下载并安装)。我喜欢这个文章和示例表单代码项目看看这个codeproject.com/KB/cs/IFilter.aspx for MS Office 2007 这里是 MS Office 2007 过滤器包microsoft.com/downloads/… 可以,只要您安装了 PDF iFilter。您可以通过安装 Acrobat Reader(随 iFilter 一起安装)或单独安装 iFilter (adobe.com/support/downloads/detail.jsp?ftpID=4025) 来完成此操作。 [注意:其他 PDF iFilter 可用:)] 2 个快速问答 - a) 我目前正在使用此处列出的方法 - codeproject.com/KB/cs/PDFToText.aspx 从 PDF 中提取文本。使用 IFilter 会有什么不同? b)在您链接的 IFilter 方法中,作者执行以下操作: TextReader reader=new FilterReader(fileName);我在 ASP.NET 中使用 FileUpload 控件,但我无法获取文件名的路径,因为为了安全起见,它没有在服务器端公开。我只能对服务器端的 fileUpload 控件执行以下操作: Stream str = fileUpload1.FileContent;字节 b[] = fileUpload1.FileBytes;【参考方案3】:

Tika 非常有用,可以轻松从不同类型的文档中提取文本,包括 microsoft office 文件。

您可以使用这个由 Kevin Miller 制作的精美艺术品 http://kevm.github.io/tikaondotnet/

只需添加这个 NuGet 包 https://www.nuget.org/packages/TikaOnDotNet/

然后,这一行代码就能发挥作用:

var text = new TikaOnDotNet.TextExtractor().Extract("fileName.docx  / pdf  / .... ").Text;

【讨论】:

这是你需要的包:nuget.org/packages/TikaOnDotnet.TextExtractor 这里值得注意的是,这实际上是通过 IKVM 运行 Apache Tika (java),IKVM 是 java 的 .net 运行时,所以它不是一个轻量级的解决方案。 (40MB 的二进制文件,基本上是一个完整的 java 运行时)【参考方案4】:

让我稍微纠正一下 KyleM 给出的答案。我刚刚添加了两个额外节点的处理,这会影响结果:一个负责“\t”的水平制表,另一个负责“\v”的垂直制表。代码如下:

    public static string ReadAllTextFromDocx(FileInfo fileInfo)
    
        StringBuilder stringBuilder;
        using(WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(dataSourceFileInfo.FullName, false))
        
            NameTable nameTable = new NameTable();
            XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(nameTable);
            xmlNamespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");

            string wordprocessingDocumentText;
            using(StreamReader streamReader = new StreamReader(wordprocessingDocument.MainDocumentPart.GetStream()))
            
                wordprocessingDocumentText = streamReader.ReadToEnd();
            

            stringBuilder = new StringBuilder(wordprocessingDocumentText.Length);

            XmlDocument xmlDocument = new XmlDocument(nameTable);
            xmlDocument.LoadXml(wordprocessingDocumentText);

            XmlNodeList paragraphNodes = xmlDocument.SelectNodes("//w:p", xmlNamespaceManager);
            foreach(XmlNode paragraphNode in paragraphNodes)
            
                XmlNodeList textNodes = paragraphNode.SelectNodes(".//w:t | .//w:tab | .//w:br", xmlNamespaceManager);
                foreach(XmlNode textNode in textNodes)
                
                    switch(textNode.Name)
                    
                        case "w:t":
                            stringBuilder.Append(textNode.InnerText);
                            break;

                        case "w:tab":
                            stringBuilder.Append("\t");
                            break;

                        case "w:br":
                            stringBuilder.Append("\v");
                            break;
                    
                

                stringBuilder.Append(Environment.NewLine);
            
        

        return stringBuilder.ToString();
    

【讨论】:

如果w:p里面有图片怎么提取?【参考方案5】:

使用 Microsoft Office 互操作。它免费且流畅。这是我如何从文档中提取所有单词的方法。

    using Microsoft.Office.Interop.Word;

   //Create Doc
    string docPath = @"C:\docLocation.doc";
    Application app = new Application();
    Document doc = app.Documents.Open(docPath);

    //Get all words
    string allWords = doc.Content.Text;
    doc.Close();
    app.Quit();

然后对单词做任何你想做的事情。

【讨论】:

啊,我的朋友太棒了。这现在应该是公认的答案,其余的已经过时了。 这很容易,但也很慢的解决方案。 Open XML 的速度要快“数千倍”。 它是免费的 - 它不需要你安装 Word 吗? @Chris: 来自 Matt Burland 的 catch22,我如何在 Linux 服务器上运行它? ;)【参考方案6】:

聚会有点晚了,但是——现在你不需要下载任何东西——所有东西都已经安装了 .NET: (只需确保添加对 System.IO.Compression 和 System.IO.Compression.FileSystem 的引用)

using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml;
using System.Text;
using System.IO.Compression;

public static class DocxTextExtractor

    public static string Extract(string filename)
    
        XmlNamespaceManager NsMgr = new XmlNamespaceManager(new NameTable());
        NsMgr.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");

        using (var archive = ZipFile.OpenRead(filename))
        
            return XDocument
                .Load(archive.GetEntry(@"word/document.xml").Open())
                .XPathSelectElements("//w:p", NsMgr)
                .Aggregate(new StringBuilder(), (sb, p) => p
                    .XPathSelectElements(".//w:t|.//w:tab|.//w:br", NsMgr)
                    .Select(e =>  switch (e.Name.LocalName)  case "br": return "\v"; case "tab": return "\t";  return e.Value; )
                    .Aggregate(sb, (sb1, v) => sb1.Append(v)))
                .ToString();
        
    

【讨论】:

这看起来是一个很好的解决方案,但我无法完成这项工作,因为我遇到了一个错误:Number of entries expected in End Of Central Directory does not correspond to number of entries in Central Directory. 该消息似乎是一个 ZipFile 压缩文件(即本例中的 docx 文件)已损坏的概念...... 这不起作用,因为它不保留行尾。【参考方案7】:

简单!

这两个步骤将带您到达那里:

1) 使用Office Interop library 将 DOC 转换为 DOCX 2)使用DOCX2TXT从新的DOCX中提取文本

1) 的链接很好地解释了如何进行转换,甚至还有代码示例。

2) 的替代方法是在 C# 中解压缩 DOCX 文件并扫描您需要的文件。您可以阅读 ZIP 文件的结构here。

编辑:啊,是的,我忘了指出,正如 Skurmedel 在下面所做的那样,您必须在要进行转换的系统上安装 Office。

【讨论】:

Office 互操作库唯一可悲的部分是您需要安装 Office。 Interop 可用,但应尽可能避免使用。 Microsoft Word 12.0 对象库 --> 这不在我的添加引用列表中,右键单击添加引用。是否有另一种方法必须输入 Microsoft Word 12.0 对象库,以便我可以阅读 word 文档。 互操作在 Godaddy 主机中不起作用。 Godday 不支持 Office。【参考方案8】:

我曾经做过一个 docx 文本提取器,非常简单。基本上 docx 和我认为的其他(新)格式是一个带有一堆 XML 文件的 zip 文件。可以使用 XmlReader 并仅使用 .NET 类来提取文本。

我没有代码了,看起来:(,但我找到了一个有类似solution的人。

如果您需要阅读 .doc 和 .xls 文件,也许这对您不可行,因为它们是二进制格式,可能更难解析。

还有OpenXML SDK,虽然仍在 CTP 中,由 Microsoft 发布。

【讨论】:

这真是太棒了!我已经完成了 docx,剩下的呢? 您可以“连接”到 xslx 文件,就像我认为使用 ODCB 的数据库一样。我认为一个非常麻烦的解决方案。我不知道如何阅读 .doc 文件或 .xls 文件,所以我无法帮助你。这是 .xls 文件的参考:sc.openoffice.org/excelfileformat.pdf 我在 XLSX 上找不到比规范本身更好的东西了:ecma-international.org/publications/files/ECMA-ST/…【参考方案9】:

如果您正在寻找 asp.net 选项,除非您在服务器上安装 Office,否则互操作将无法工作。即使那样,微软也表示不要这样做。

我使用了 Spire.Doc,效果很好。 Spire.Doc download 它甚至可以读取实际上是 .txt 但保存为 .doc 的文档。他们有免费和付费版本。您还可以获得一个试用许可证,该许可证会从您创建的文档中删除一些警告,但我没有创建任何警告,只是搜索了它们,因此免费版本就像一个魅力。

【讨论】:

Erik Felde,你能给 Spire.Doc 上的 asp.net 举一些例子吗【参考方案10】:

在 C# 中从 Office 文档中提取文本的合适选项之一是 GroupDocs.Parser for .NET API。以下是提取简单文本和格式化文本的代码示例。

提取文本

// Create an instance of Parser class
using(Parser parser = new Parser("sample.docx"))

    // Extract a text into the reader
    using(TextReader reader = parser.GetText())
    
        // Print a text from the document
        // If text extraction isn't supported, a reader is null
        Console.WriteLine(reader == null ? "Text extraction isn't supported" : reader.ReadToEnd());
    

提取格式化文本

// Create an instance of Parser class
using (Parser parser = new Parser("sample.docx"))

    // Extract a formatted text into the reader
    using (TextReader reader = parser.GetFormattedText(new FormattedTextOptions(FormattedTextMode.html)))
    
        // Print a formatted text from the document
        // If formatted text extraction isn't supported, a reader is null
        Console.WriteLine(reader == null ? "Formatted text extraction isn't suppported" : reader.ReadToEnd());
    

披露:我在 GroupDocs 担任开发人员宣传员。

【讨论】:

以上是关于如何在 C# 中从 MS Office 文档中提取文本的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中从 HTML 文件中提取图像 url

如何在c#中从pdf文档中获取标签

在 C# 中从 .docx 文件的页眉和页脚获取图像

如何在 MFC 中支持多种文档类型,例如 MS Office 应用程序或 Visual Studio

如何以编程方式重新启用 MS Office 禁用文件列表中的文档

如何在 C# 中使用 Microsoft.Office.Interop.Excel.Application 保存打开的文档?