דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. קוד C# לחילוץ טקסט מקבצי וורד

קוד C# לחילוץ טקסט מקבצי וורד

מתוזמן נעוץ נעול הועבר תכנות
11 פוסטים 3 כותבים 238 צפיות
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • pcinfogmachP מנותק
    pcinfogmachP מנותק
    pcinfogmach
    כתב ב נערך לאחרונה על ידי pcinfogmach
    #1
    using DocumentFormat.OpenXml.Packaging;
    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Xml;
    using WordInterop = Microsoft.Office.Interop.Word;
    
    namespace MsWordTextExtractor
    {
        public static class DocxTextExtractor
        {
            public static string Extract(string filePath)
            {
                try
                {
                    return ReadAllTextParts(filePath);
                }
                catch
                {
                    return WordInteropExtractor(filePath);
                }
            }
    
            static string ReadAllTextParts(string filePath)
            {
                StringBuilder stb = new StringBuilder();
                using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(filePath, false))
                {
                    var mainPart = wordprocessingDocument.MainDocumentPart;
                    stb.AppendLine(ReadTextPart(mainPart.GetStream()));
    
                    if (mainPart.FootnotesPart != null)
                    {
                        string footNotes = ReadFootnotesPart(mainPart.FootnotesPart.GetStream());
                        if (!string.IsNullOrEmpty(footNotes))
                        {
                            stb.AppendLine();
                            stb.AppendLine(footNotes);
                        }
                    }
    
                    if (mainPart.EndnotesPart != null)
                    {
                        string footNotes = ReadFootnotesPart(mainPart.FootnotesPart.GetStream());
                        if (!string.IsNullOrEmpty(footNotes))
                        {
                            stb.AppendLine();
                            stb.AppendLine(footNotes);
                        }
                    }
                }
                return stb.ToString();
            }
    
            static string ReadTextPart(Stream partStream)
            {
                NameTable nameTable = new NameTable();
                XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(nameTable);
                xmlNamespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
                StringBuilder stringBuilder = new StringBuilder();
    
                XmlDocument xmlDocument = new XmlDocument(nameTable);
                xmlDocument.Load(partStream);
    
                XmlNodeList paragraphNodes = xmlDocument.SelectNodes("//w:p", xmlNamespaceManager);
                foreach (XmlNode paragraphNode in paragraphNodes)
                {
                    ReadTextContent(stringBuilder, paragraphNode, xmlNamespaceManager);
                    stringBuilder.Append(Environment.NewLine);
                }
                return stringBuilder.ToString().Trim();
            }
    
            static string ReadFootnotesPart(Stream partStream)
            {
                NameTable nameTable = new NameTable();
                XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(nameTable);
                xmlNamespaceManager.AddNamespace("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
                StringBuilder stringBuilder = new StringBuilder();
    
                XmlDocument xmlDocument = new XmlDocument(nameTable);
                xmlDocument.Load(partStream);
    
                XmlNodeList footnoteNodes = xmlDocument.SelectNodes("//w:footnote | .//w:endnote", xmlNamespaceManager);
                foreach (XmlNode footnoteNode in footnoteNodes)
                {
                    string footnoteId = footnoteNode.Attributes["w:id"].Value;
                    if (footnoteId == "-1" || footnoteId == "0") { continue; }
                    stringBuilder.Append($"{footnoteId}");
    
                    ReadTextContent(stringBuilder, footnoteNode, xmlNamespaceManager);
    
                    stringBuilder.AppendLine();
                }
                return stringBuilder.ToString().Trim();
            }
    
            static void ReadTextContent(StringBuilder stringBuilder, XmlNode xmlNode, XmlNamespaceManager xmlNamespaceManager)
            {
                XmlNodeList textNodes = xmlNode.SelectNodes(".//w:t | .//w:tab | .//w:br | .//w:footnoteReference | .//w:numPr", 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;
    
                        case "w:footnoteReference":
                            string footnoteId = textNode.Attributes["w:id"].Value;
                            stringBuilder.Append($"{footnoteId}");
                            break;
    
                        case "w:numPr":
                            XmlNode ilvlNode = textNode.SelectSingleNode(".//w:ilvl", xmlNamespaceManager);
                            XmlNode numIdNode = textNode.SelectSingleNode(".//w:numId", xmlNamespaceManager);
                            if (ilvlNode != null && numIdNode != null)
                            {                       
                                stringBuilder.Append("*");
                            }
                            break;
                    }
                }
            }
    
            public static string WordInteropExtractor(string filePath)
            {
                string tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(filePath) + ".txt");
    
    
                try
                {
                    using (WordApp wordApp = new WordApp())
                    {
                        WordInterop.Document doc = null;
                        bool isFileAlreadyOpen = false;
    
                        foreach (WordInterop.Document openDoc in wordApp.App.Documents)
                        {
                            if (openDoc.FullName.Equals(Path.GetFullPath(filePath), StringComparison.OrdinalIgnoreCase))
                            {
                                doc = openDoc;
                                isFileAlreadyOpen = true;
                                break;
                            }
                        }
    
                        if (doc == null) doc = wordApp.App.Documents.Open(filePath, ReadOnly: true, Visible: false);
    
                        var originalFormat = doc.SaveFormat;
                        doc.SaveAs2(tempFilePath, WordInterop.WdSaveFormat.wdFormatUnicodeText, Encoding: 65001, AddToRecentFiles: false);
                        if (isFileAlreadyOpen) doc.SaveAs2(filePath, originalFormat);
    
                        if (doc != null && !isFileAlreadyOpen) doc.Close(WordInterop.WdSaveOptions.wdDoNotSaveChanges);
                    }
    
                    return File.ReadAllText(tempFilePath);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return string.Empty;
                }
                finally
                {
                    if (File.Exists(tempFilePath)) File.Delete(tempFilePath);
                }
            }
        }
    
        class WordApp : IDisposable
        {
            public Microsoft.Office.Interop.Word.Application App;
            bool isNewApp;
    
            public WordApp()
            {
                try
                {
                    App = (WordInterop.Application)Marshal.GetActiveObject("Word.Application");
                }
                catch (COMException)
                {
                    App = new WordInterop.Application();
                    isNewApp = true;
                }
            }
    
            public void Dispose()
            {
                if (isNewApp && App != null)
                {
                    App.Quit();
                    Marshal.ReleaseComObject(App);
                }
            }
        }
    }
    
    
    
    

    עריכה:
    מי שרוצה לחלץ טקסט מקבצי doc ללא שימוש באופיס יכול להשתמש בספרייה NPOI.HWPF

    עם הקוד דלהלן

    internal class NpoiDocExtractor
    {
        public static string ExtractTextFromDoc(string filePath)
        {
            using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                HWPFDocument doc = new HWPFDocument(fileStream);
                WordExtractor extractor = new WordExtractor(doc);
                return extractor.Text;
            }
        }
    }
    

    הספרייה עושה עבודה די טובה החסרון היחיד שלה הוא שהיא לא מחלצת את מספרי ההערות

    גמ"ח מידע מחשבים ואופיס

    yossizY תגובה 1 תגובה אחרונה
    2
    • yossizY מנותק
      yossizY מנותק
      yossiz
      השיב לpcinfogmach ב נערך לאחרונה על ידי
      #2

      @pcinfogmach באיזה מקרה לא עובדת השיטה הראשונה בגלל IOException וצריך לעבור לשיטה השניה?

      📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

      pcinfogmachP dovidD 2 תגובות תגובה אחרונה
      1
      • yossizY מנותק
        yossizY מנותק
        yossiz
        כתב ב נערך לאחרונה על ידי
        #3

        הערה קטנה:
        אין לך ירידת שורה בין סוף הטקסט הראשי לתחילת טקסט ההערות
        וכן בין סוף הערות שוליים לתחילת הערות סוף

        עוד הערה קטנה: אני מבין שבצורך שלך זה לא כל כך רלוונטי, אבל לצרכים אחרים היה כדאי לקבל את מספרי ההערות

        📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

        pcinfogmachP 2 תגובות תגובה אחרונה
        1
        • yossizY מנותק
          yossizY מנותק
          yossiz
          כתב ב נערך לאחרונה על ידי yossiz
          #4

          עוד הערה:
          מאיפה הרעיון ש:w:br שווה ל-\v?
          באמת נראה שאתה צודק שוורד ברמה כלשהו מתייחס לתו שמכניסים על ידי shift+return כתו ה-ASCII עם ערך 11
          זה נוגע לסקריפטים ב-VBA. אפשר גם לחפש תו כזה על ידי חיפוש של ^11
          בדקתי בוורד של היום ובייצוא לטקסט הוא מתרגם את זה לירידת שורה נורמלית, אני לא יודע אם זה נכון בכל הגירסאות ההיסטוריות של וורד
          בכל מקרה זה תו יחסית נדיר במסמכים

          📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

          תגובה 1 תגובה אחרונה
          1
          • pcinfogmachP מנותק
            pcinfogmachP מנותק
            pcinfogmach
            השיב לyossiz ב נערך לאחרונה על ידי pcinfogmach
            #5

            @yossiz
            בעיקר במקרה שהמסמך כבר פתוח ב-office
            תכלס שיניתי כעת את הקוד שיעבור לשיטה השניה על כל שגיאה כדי שיכלול את מה ש-DOvid כתב להלן

            גמ"ח מידע מחשבים ואופיס

            תגובה 1 תגובה אחרונה
            1
            • dovidD מנותק
              dovidD מנותק
              dovid ניהול
              השיב לyossiz ב נערך לאחרונה על ידי
              #6

              @yossiz כתב בקוד C# לחילוץ טקסט מקבצי וורד:

              @pcinfogmach באיזה מקרה לא עובדת השיטה הראשונה בגלל IOException וצריך לעבור לשיטה השניה?

              אולי doc או פורמטים שאינם openXml?

              מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

              בכל נושא אפשר ליצור קשר dovid@tchumim.com

              yossizY תגובה 1 תגובה אחרונה
              1
              • pcinfogmachP מנותק
                pcinfogmachP מנותק
                pcinfogmach
                השיב לyossiz ב נערך לאחרונה על ידי pcinfogmach
                #7

                @yossiz כתב בקוד C# לחילוץ טקסט מקבצי וורד:

                עוד הערה קטנה: אני מבין שבצורך שלך זה לא כל כך רלוונטי, אבל לצרכים אחרים היה כדאי לקבל את מספרי ההערות

                אבדוק את זה תודה.

                תכלס לבינתיים
                בשיטה השניה מקבלים הכל כולל פיסקאות ממוספרות
                מי שדחוף לו כל זה יכול להשתמש רק בשיטה השניה
                החסרונות בשיטה השניה הם:
                א. איטיות
                ב. צריך שיהיה וורד מותקן במחשב (תאמינו או לא אבל יש אנשים שאין להם וורד במחשב)

                גמ"ח מידע מחשבים ואופיס

                תגובה 1 תגובה אחרונה
                1
                • yossizY מנותק
                  yossizY מנותק
                  yossiz
                  השיב לdovid ב נערך לאחרונה על ידי
                  #8

                  @dovid אחרי שינוי זה: -

                  @pcinfogmach כתב בקוד C# לחילוץ טקסט מקבצי וורד:

                  תכלס שיניתי כעת את הקוד שיעבור לשיטה השניה על כל שגיאה

                  עכשיו הקוד באמת יעבוד על פורמטים אחרים. לפי הקוד הקודם זה עבר לשיטה השניה רק על IOException, ועבור שגיאה של פורמט לא נכון היה טיפול שונה, אני כבר לא זוכר מה היה שם...

                  📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                  תגובה 1 תגובה אחרונה
                  2
                  • pcinfogmachP מנותק
                    pcinfogmachP מנותק
                    pcinfogmach
                    השיב לyossiz ב נערך לאחרונה על ידי pcinfogmach
                    #9

                    @yossiz כתב בקוד C# לחילוץ טקסט מקבצי וורד:

                    עוד הערה קטנה: אני מבין שבצורך שלך זה לא כל כך רלוונטי, אבל לצרכים אחרים היה כדאי לקבל את מספרי ההערות

                    הוספתי כעת
                    פיסקאות ממוספרות הצלחתי לסמן רק עם * ולא עם המספרים

                    גמ"ח מידע מחשבים ואופיס

                    yossizY תגובה 1 תגובה אחרונה
                    1
                    • yossizY מנותק
                      yossizY מנותק
                      yossiz
                      השיב לpcinfogmach ב נערך לאחרונה על ידי yossiz
                      #10

                      @pcinfogmach אכן אני רואה שקצת מסובך לקבל את המספרים של פיסקאות ממוספרות
                      (אתה יכול בינתיים למחוק את האיזכורים בקוד ל-NumberingDefinitionsPart מכיון שבסוף אתה לא משתמש בו)

                      📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                      pcinfogmachP תגובה 1 תגובה אחרונה
                      1
                      • pcinfogmachP מנותק
                        pcinfogmachP מנותק
                        pcinfogmach
                        השיב לyossiz ב נערך לאחרונה על ידי pcinfogmach
                        #11

                        @yossiz
                        הצלחתי בס"ד לקבל גם את הפסקאות הממוספרות הקוד גם הרבה פחות מסורבל עכשיו
                        הוספתי גם קוד לחילוץ מקבצי doc ללא השתמשות בוורד למי שרוצה

                        גמ"ח מידע מחשבים ואופיס

                        תגובה 1 תגובה אחרונה
                        0

                        בא תתחבר לדף היומי!
                        • התחברות

                        • אין לך חשבון עדיין? הרשמה

                        • התחברו או הירשמו כדי לחפש.
                        • פוסט ראשון
                          פוסט אחרון
                        0
                        • דף הבית
                        • קטגוריות
                        • פוסטים אחרונים
                        • משתמשים
                        • חיפוש
                        • חוקי הפורום