غالبًا ما يتم إجراء استخراج النص من مستندات Word في سيناريوهات مختلفة. على سبيل المثال ، لتحليل النص ، لاستخراج أقسام معينة من المستند ودمجها في مستند واحد ، وهكذا. في هذه المقالة ، ستتعلم كيفية استخراج النص من مستندات Word برمجيًا في C#. علاوة على ذلك ، سوف نتناول كيفية استخراج المحتوى بين عناصر محددة مثل الفقرات والجداول وما إلى ذلك بشكل ديناميكي.
مكتبة C# لاستخراج النص من مستندات Word
Aspose.Words for .NET هي مكتبة قوية تسمح لك بإنشاء مستندات MS Word من البداية. علاوة على ذلك ، فإنه يتيح لك معالجة مستندات Word الحالية للتشفير والتحويل واستخراج النص وما إلى ذلك. سنستخدم هذه المكتبة لاستخراج النص من مستندات Word DOCX أو DOC. يمكنك تنزيل DLL الخاص بواجهة برمجة التطبيقات أو تثبيته مباشرة من NuGet باستخدام وحدة تحكم مدير الحزم.
PM> Install-Package Aspose.Words
استخراج النص في مستندات Word باستخدام C#
يتكون مستند MS Word من عناصر مختلفة تشمل فقرات وجداول وصور وما إلى ذلك. لذلك ، يمكن أن تختلف متطلبات استخراج النص من سيناريو إلى آخر. على سبيل المثال ، قد تحتاج إلى استخراج نص بين الفقرات والإشارات المرجعية والتعليقات وما إلى ذلك.
يتم تمثيل كل نوع من العناصر في مستند Word كعقدة. لذلك ، لمعالجة مستند ، سيتعين عليك اللعب بالعقد. لذلك دعونا نبدأ ونرى كيفية استخراج النص من مستندات Word في سيناريوهات مختلفة.
استخراج نص من مستند Word في C#
في هذا القسم ، سنقوم بتنفيذ مستخرج نص C# لمستندات Word وسيكون سير العمل لاستخراج النص كما يلي:
- أولاً ، سنحدد العقد التي نريد تضمينها في عملية استخراج النص.
- بعد ذلك ، سنقوم باستخراج المحتوى بين العقد المحددة (بما في ذلك أو استبعاد عقد البداية والنهاية).
- أخيرًا ، سنستخدم استنساخ العقد المستخرجة ، على سبيل المثال لإنشاء مستند Word جديد يتكون من محتوى مستخرج.
لنكتب الآن طريقة باسم ExtractContent سنمرر إليها العقد وبعض المعلمات الأخرى لإجراء استخراج النص. ستعمل هذه الطريقة على تحليل المستند واستنساخ العقد. فيما يلي المعلمات التي سنمررها إلى هذه الطريقة.
- StartNode و EndNode كنقطتي بداية ونهاية لاستخراج المحتوى ، على التوالي. يمكن أن تكون هذه العقد على مستوى الكتلة (فقرة ، جدول) أو مستوى مضمن (على سبيل المثال ، Run ، FieldStart ، BookmarkStart وما إلى ذلك).
- لتمرير حقل ، يجب عليك تمرير كائن FieldStart المقابل.
- لتمرير الإشارات المرجعية ، يجب تمرير عقد BookmarkStart و BookmarkEnd.
- للتعليقات ، يجب استخدام عقدتي CommentRangeStart و CommentRangeEnd.
- يحدد IsInclusive ما إذا كانت العلامات مضمنة في الاستخراج أم لا. إذا تم تعيين هذا الخيار على false وتم تمرير نفس العقدة أو العقد المتتالية ، فسيتم إرجاع قائمة فارغة.
فيما يلي التنفيذ الكامل لأسلوب ExtractContent الذي يستخرج المحتوى بين العقد التي تم تمريرها.
public static ArrayList ExtractContent(Node startNode, Node endNode, bool isInclusive)
{
// تحقق أولاً من أن العقد التي تم تمريرها إلى هذه الطريقة صالحة للاستخدام.
VerifyParameterNodes(startNode, endNode);
// قم بإنشاء قائمة لتخزين العقد المستخرجة.
ArrayList nodes = new ArrayList();
// احتفظ بسجل للعقد الأصلية التي تم تمريرها إلى هذه الطريقة حتى نتمكن من تقسيم عقد التحديد إذا لزم الأمر.
Node originalStartNode = startNode;
Node originalEndNode = endNode;
// استخراج المحتوى بناءً على عقد مستوى الكتلة (الفقرات والجداول).اجتياز العقد الأصلية للعثور عليها.
// سنقوم بتقسيم محتوى العقد الأولى والأخيرة اعتمادًا على ما إذا كانت عُقد التحديد مضمنة
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;
// العقدة الحالية التي نستخرجها من المستند.
Node currNode = startNode;
// ابدأ في استخراج المحتوى. قم بمعالجة جميع عقد مستوى الكتلة وقم على وجه التحديد بتقسيم العقد الأولى والأخيرة عند الحاجة لذلك يتم الاحتفاظ بتنسيق الفقرة.
// الطريقة أكثر تعقيدًا من المستخرج العادي حيث نحتاج إلى الاستخراج باستخدام العقد المضمنة والحقول والإشارات المرجعية وما إلى ذلك لجعلها مفيدة حقًا.
while (isExtracting)
{
// استنساخ العقدة الحالية وتوابعها للحصول على نسخة.
Node cloneNode = currNode.Clone(true);
isEndingNode = currNode.Equals(endNode);
if ((isStartingNode || isEndingNode) && cloneNode.IsComposite)
{
// نحتاج إلى معالجة كل علامة على حدة ، لذا قم بتمريرها إلى طريقة منفصلة بدلاً من ذلك.
if (isStartingNode)
{
ProcessMarker((CompositeNode)cloneNode, nodes, originalStartNode, isInclusive, isStartingNode, isEndingNode);
isStartingNode = false;
}
// يجب أن يكون الشرطي منفصلاً لأن علامات بداية ونهاية مستوى الكتلة ربما تكون نفس العقدة.
if (isEndingNode)
{
ProcessMarker((CompositeNode)cloneNode, nodes, originalEndNode, isInclusive, isStartingNode, isEndingNode);
isExtracting = false;
}
}
else
// العقدة ليست علامة بداية أو نهاية ، ما عليك سوى إضافة النسخة إلى القائمة.
nodes.Add(cloneNode);
// انتقل إلى العقدة التالية واستخرجها. إذا كانت العقدة التالية خالية ، فهذا يعني أن باقي المحتوى موجود في قسم مختلف.
if (currNode.NextSibling == null && isExtracting)
{
// انتقل إلى القسم التالي.
Section nextSection = (Section)currNode.GetAncestor(NodeType.Section).NextSibling;
currNode = nextSection.Body.FirstChild;
}
else
{
// انتقل إلى العقدة التالية في الجسم.
currNode = currNode.NextSibling;
}
}
// أعد العقد بين علامات العقدة.
return nodes;
}
بعض الطرق المساعدة مطلوبة أيضًا بواسطة طريقة ExtractContent لإنجاز عملية استخراج النص ، والتي ترد أدناه.
public static List<Paragraph> ParagraphsByStyleName(Document doc, string styleName)
{
// قم بإنشاء مصفوفة لتجميع فقرات من النمط المحدد.
List<Paragraph> paragraphsWithStyle = new List<Paragraph>();
NodeCollection paragraphs = doc.GetChildNodes(NodeType.Paragraph, true);
// ابحث في جميع الفقرات للعثور على تلك ذات النمط المحدد.
foreach (Paragraph paragraph in paragraphs)
{
if (paragraph.ParagraphFormat.Style.Name == styleName)
paragraphsWithStyle.Add(paragraph);
}
return paragraphsWithStyle;
}
private static void VerifyParameterNodes(Node startNode, Node endNode)
{
// الترتيب الذي تتم به هذه الفحوصات مهم.
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");
// تحقق من أن عقدة النهاية بعد عقدة البداية في شجرة DOM
// تحقق أولاً مما إذا كانوا في أقسام مختلفة ، ثم إذا لم يتحققوا من موقعهم في نفس القسم الذي يتواجدون فيه.
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)
{
// اختبر ما إذا كانت العقدة تابعة لعقدة فقرة أو جدول وأيضًا ليست فقرة أو جدولًا ، فمن الممكن أن تكون فقرة داخل فئة تعليق مما يجعلها غير صحيحة.
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)
{
// إذا كنا نتعامل مع عقدة على مستوى الكتلة ، فما عليك سوى معرفة ما إذا كان يجب تضمينها وإضافتها إلى القائمة.
if (!IsInline(node))
{
// لا تقم بإضافة العقدة مرتين إذا كانت العلامات هي نفس العقدة
if (!(isStartMarker && isEndMarker))
{
if (isInclusive)
nodes.Add(cloneNode);
}
return;
}
// إذا كانت العلامة عبارة عن عقدة FieldStart ، تحقق مما إذا كان سيتم تضمينها أم لا.
// نفترض من أجل البساطة أن يظهر FieldStart و FieldEnd في نفس الفقرة.
if (node.NodeType == NodeType.FieldStart)
{
// إذا كانت العلامة عبارة عن عقدة بداية ولم يتم تضمينها ، فانتقل إلى نهاية الحقل.
// إذا كانت العلامة عبارة عن عقدة نهاية ويجب تضمينها ، فانتقل إلى حقل النهاية حتى لا تتم إزالة الحقل.
if ((isStartMarker && !isInclusive) || (!isStartMarker && isInclusive))
{
while (node.NextSibling != null && node.NodeType != NodeType.FieldEnd)
node = node.NextSibling;
}
}
// إذا كانت أي من العلامات جزءًا من تعليق ، فعندئذٍ لتضمين التعليق نفسه ، نحتاج إلى تحريك المؤشر إلى الأمام إلى التعليق
// تم العثور على العقدة بعد العقدة CommentRangeEnd.
if (node.NodeType == NodeType.CommentRangeEnd)
{
while (node.NextSibling != null && node.NodeType != NodeType.Comment)
node = node.NextSibling;
}
// ابحث عن العقدة المقابلة في العقدة المستنسخة بالفهرس وأعدها.
// إذا كانت عقدة البداية والنهاية هي نفسها ، فربما تمت إزالة بعض العقد الفرعية بالفعل. اطرح
// الفرق للحصول على الفهرس الصحيح.
int indexDiff = node.ParentNode.ChildNodes.Count - cloneNode.ChildNodes.Count;
// عدد العقدة الفرعية متطابق.
if (indexDiff == 0)
node = cloneNode.ChildNodes[node.ParentNode.IndexOf(node)];
else
node = cloneNode.ChildNodes[node.ParentNode.IndexOf(node) - indexDiff];
// قم بإزالة العقد حتى / من العلامة.
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();
}
// بعد معالجة العقدة المركبة قد تصبح فارغة. إذا لم يتم تضمينه.
if (!(isStartMarker && isEndMarker))
{
if (cloneNode.HasChildNodes)
nodes.Add(cloneNode);
}
}
public static Document GenerateDocument(Document srcDoc, ArrayList nodes)
{
// قم بإنشاء مستند فارغ.
Document dstDoc = new Document();
// أزل الفقرة الأولى من المستند الفارغ.
dstDoc.FirstSection.Body.RemoveAllChildren();
// قم باستيراد كل عقدة من القائمة إلى المستند الجديد. احتفظ بالتنسيق الأصلي للعقدة.
NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.KeepSourceFormatting);
foreach (Node node in nodes)
{
Node importNode = importer.ImportNode(node, true);
dstDoc.FirstSection.Body.AppendChild(importNode);
}
// إرجاع المستند الذي تم إنشاؤه.
return dstDoc;
}
نحن الآن جاهزون لاستخدام هذه الأساليب واستخراج النص من مستند Word.
استخراج نص بين الفقرات في مستند Word
دعونا نرى كيفية استخراج المحتوى بين فقرتين في مستند Word DOCX. فيما يلي خطوات إجراء هذه العملية في C#.
- أولاً ، قم بتحميل مستند Word باستخدام فئة المستند.
- احصل على مرجع لفقرات البداية والنهاية في كائنين باستخدام طريقة Document.FirstSection.Body.GetChild (NodeType.PARAGRAPH، int، boolean).
- استدعاء طريقة ExtractContent (startPara ، endPara ، True) لاستخراج العقد في كائن.
- استدعاء الأسلوب المساعد GenerateDocument (Document ، extractedNodes) لإنشاء مستند يتكون من المحتوى المستخرج.
- أخيرًا ، احفظ المستند المرتجع باستخدام طريقة Document.Save(string).
يوضح نموذج التعليمات البرمجية التالي كيفية استخراج النص بين الفقرتين السابعة والحادية عشرة في مستند Word في C#.
// تحميل مستند Word
Document doc = new Document("document.docx");
// اجمع العقد (تستخدم طريقة GetChild فهرسًا قائمًا على 0)
Paragraph startPara = (Paragraph)doc.FirstSection.Body.GetChild(NodeType.Paragraph, 6, true);
Paragraph endPara = (Paragraph)doc.FirstSection.Body.GetChild(NodeType.Paragraph, 10, true);
// استخرج المحتوى بين هذه العقد في المستند. قم بتضمين هذه العلامات في الاستخراج.
ArrayList extractedNodes = ExtractContent(startPara, endPara, true);
// أدخل المحتوى في مستند جديد واحفظه على القرص.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");
استخراج النص بين أنواع العقد المختلفة في مستند Word
يمكنك أيضًا استخراج المحتوى بين أنواع العقد المختلفة. للتوضيح ، دعنا نستخرج المحتوى بين فقرة وجدول ونحفظه في مستند Word جديد. فيما يلي خطوات إجراء هذه العملية.
- قم بتحميل مستند Word باستخدام فئة المستند.
- احصل على مرجع لعقدتي البداية والنهاية في كائنين باستخدام طريقة Document.FirstSection.Body.GetChild (NodeType، int، boolean).
- استدعاء طريقة ExtractContent (startPara ، endPara ، True) لاستخراج العقد في كائن.
- استدعاء الأسلوب المساعد GenerateDocument (Document ، extractedNodes) لإنشاء مستند يتكون من المحتوى المستخرج.
- احفظ المستند المرتجع باستخدام طريقة Document.Save(string).
يُظهر نموذج التعليمات البرمجية التالي كيفية استخراج نص بين فقرة وجدول في C#.
// تحميل مستند 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);
// استخرج المحتوى بين هذه العقد في المستند. قم بتضمين هذه العلامات في الاستخراج.
ArrayList extractedNodes = ExtractContent(startPara, endTable, true);
// أدخل المحتوى في مستند جديد واحفظه على القرص.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");
استخراج النص بين الفقرات بناءً على الأنماط
دعنا الآن نتحقق من كيفية استخراج المحتوى بين الفقرات بناءً على الأنماط. للتوضيح ، سنقوم باستخراج المحتوى بين “العنوان 1” الأول و “العنوان 3” الأول في مستند Word. توضح الخطوات التالية كيفية تحقيق ذلك في C#.
- أولاً ، قم بتحميل مستند Word باستخدام فئة المستند.
- بعد ذلك ، قم باستخراج الفقرات في كائن باستخدام أسلوب مساعد ParagraphsByStyleName (المستند ، “العنوان 1”).
- استخراج الفقرات إلى كائن آخر باستخدام أسلوب مساعد ParagraphsByStyleName (المستند ، “العنوان 3”).
- قم باستدعاء طريقة ExtractContent (startPara ، endPara ، True) وتمرير العناصر الأولى في كل من مصفوفات الفقرة كمعامل أول وثاني.
- استدعاء الأسلوب المساعد GenerateDocument (Document ، extractedNodes) لإنشاء مستند يتكون من المحتوى المستخرج.
- أخيرًا ، احفظ المستند المرتجع باستخدام طريقة Document.Save(string).
يوضح نموذج التعليمات البرمجية التالي كيفية استخراج المحتوى بين الفقرات بناءً على الأنماط.
// تحميل مستند Word
Document doc = new Document("document.docx");
// قم بتجميع قائمة بالفقرات باستخدام أنماط العناوين الخاصة بها.
List<Paragraph> parasStyleHeading1 = ParagraphsByStyleName(doc, "Heading 1");
List<Paragraph> parasStyleHeading3 = ParagraphsByStyleName(doc, "Heading 3");
// استخدم المثيل الأول للفقرات بهذه الأنماط.
Node startPara1 = (Node)parasStyleHeading1[0];
Node endPara1 = (Node)parasStyleHeading3[0];
// استخرج المحتوى بين هذه العقد في المستند. لا تقم بتضمين هذه العلامات في الاستخراج.
ArrayList extractedNodes = ExtractContent(startPara1, endPara1, false);
// أدخل المحتوى في مستند جديد واحفظه على القرص.
Document dstDoc = GenerateDocument(doc, extractedNodes);
dstDoc.Save("output.docx");
اقرأ أكثر
يمكنك استكشاف سيناريوهات أخرى لاستخراج النص من مستندات Word باستخدام مقالة التوثيق هذه.
احصل على ترخيص API مجاني
يمكنك الحصول على ترخيص مؤقت لاستخدام Aspose.Words لـ .NET بدون قيود تقييم.
استنتاج
في هذه المقالة ، تعلمت كيفية استخراج نص من مستندات MS Word باستخدام C#. علاوة على ذلك ، لقد رأيت كيفية استخراج المحتوى بين أنواع متشابهة أو مختلفة من العقد في مستند Word برمجيًا. وبالتالي ، يمكنك بناء مستخرج نصوص MS Word الخاص بك في C#. بالإضافة إلى ذلك ، يمكنك استكشاف ميزات أخرى لـ Aspose.Words for .NET باستخدام التوثيق. في حال كان لديك أي أسئلة ، لا تتردد في إخبارنا عبر المنتدى.
أنظر أيضا
تلميح: قد ترغب في التحقق من محول Aspose PowerPoint to Word لأنه يوضح العرض التقديمي الشهير لعملية تحويل مستند Word.