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

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

【问题讨论】:

    标签: c# ms-office text-extraction


    【解决方案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;
    

    【讨论】:

    • 这里值得注意的是,这实际上是通过 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 担任开发人员宣传员。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-05
      • 1970-01-01
      • 1970-01-01
      • 2011-10-06
      • 1970-01-01
      • 2014-07-15
      • 2011-01-18
      • 2016-02-12
      相关资源
      最近更新 更多