VBA: كيفية العثور على قيمة في عمود (مع مثال)

دليل أكاديمي شامل يشرح كيفية استخدام لغة VBA للعثور على قيمة داخل عمود في Excel بدقة، مع استعراض المعاملات البرمجية، ومعالجة الأخطاء، وأمثلة تطبيقية متقدمة.

Mohammed looti أكاديمي وباحث متخصص في علم النفس
تاريخ النشر
تمت المراجعة العلمية · د. مروة عبد العظيم · 20 أكتوبر، 2026
مراجعة وتدقيق علمي معتمد تاريخ التدقيق: 20 أكتوبر، 2026
د. مروة عبد العظيم دكتوراه في علم النفس
عضو هيئة التدريس • جامعة كربلاء
معايير التدقيق والاعتماد السريري

يخضع هذا المحتوى لمعايير ضبط الجودة والتدقيق العلمي والأكاديمي الصارمة في شبكة علم النفس العربي، لضمان صحة المعلومات ودقتها السريرية ومطابقتها لأحدث الأدلة والبراهين الصادرة عن الجمعيات النفسية والطبية المعتمدة (APA / WHO).

تعد إدارة البيانات وتحليلها الركيزة الأساسية لاتخاذ القرارات الرشيدة في المنظومات المؤسسية والأكاديمية المعاصرة. ومع تنامي الاعتماد على جداول البيانات الإلكترونية، برزت الحاجة الملحة إلى تجاوز العمليات اليدوية المعرضة للخطأ البشري، والتحول نحو الأتمتة المنهجية التي تضمن السرعة والدقة المتناهية. في هذا السياق، تبرز لغة البرمجة Visual Basic for Applications، المعروفة اختصاراً بـ VBA، كأداة تطوير استثنائية مدمجة داخل حزمة تطبيقات مايكروسوفت أوفيس، تتيح للمستخدمين تحويل المصنفات التقليدية إلى برمجيات تفاعلية متطورة قادرة على معالجة ملايين السجلات بكفاءة منقطعة النظير.

يمثل البحث عن القيم المحددة داخل أعمدة جداول البيانات أحد أكثر الإجراءات الروتينية تكراراً وأهمية في بيئات العمل الحوسبية. سواء تعلق الأمر باستخراج معرفات الموظفين، أو تتبع السجلات الأكاديمية للطلاب، أو فحص القيود المحاسبية، فإن كفاءة آلية البحث تحدد الأداء العام للنظام البرمجي بأكمله. إن الاعتماد على دالة البحث البرمجية المتخصصة Range.Find يوفر حلاً هندسياً فائق السرعة مقارنة بالحلقات التكرارية التقليدية التي تفحص الخلايا خلية تلو الأخرى، مما يقلل من العبء الحسابي الواقع على المعالج وذاكرة النظام.

يتناول هذا الدليل الشامل والمفصل كيفية استخدام لغة VBA للعثور على القيم النصية والرقمية داخل عمود محدد في برنامج إكسيل، بدءاً من التشريح النحوي للدوال البرمجية، ومروراً بالتحليل الدقيق لكافة المعاملات الاختيارية والإلزامية، ووصولاً إلى تطبيق أفضل الممارسات البرمجية وتفادي الأفخاخ التقنية الشائعة مثل ظاهرة الإعدادات المستمرة. كما يقدم الدليل أمثلة برمجية عملية قابلة للتطبيق المباشر، مدعومة بتحليلات نظرية وتطبيقية تعزز الفهم العميق لبيئة تطوير التطبيقات المكتبية وتكامل نظم المعلومات (Sarker & Sahay, 2003).

1. مقدمة إلى لغة البرمجة VBA وأهمية أتمتة البحث في جداول البيانات

1.1 مفهوم برمجة التطبيقات في إكسيل ودورها في إدارة البيانات

تعرف بيئة التطوير Visual Basic for Applications (VBA) بأنها بيئة برمجة موجهة بالأحداث طورتها شركة مايكروسوفت لتمكين أتمتة المهام المعقدة وتوسيع القدرات الوظيفية لتطبيقات حزمة أوفيس، وعلى رأسها برنامج إكسيل. تم إطلاق هذه اللغة لأول مرة مع إصدار إكسيل 5.0 في عام 1993، مستندة إلى المفاهيم التأسيسية التي وضعها رواد البرمجة المرئية، مما شكل نقلة نوعية في كيفية تفاعل المستخدمين والباحثين مع جداول البيانات. في البيئات المؤسسية والأكاديمية الحديثة، لم تعد جداول البيانات مجرد أدوات لتخزين الأرقام البسيطة، بل تحولت إلى قواعد بيانات مصغرة تتطلب معالجة ديناميكية وتحليلات إحصائية متقدمة، وهو ما تجعله لغة VBA أمراً ممكناً من خلال إتاحة التحكم البرمجي الكامل في نموذج كائنات إكسيل (Excel Object Model).

إن الانتقال المنهجي من نمط المعالجة اليدوية إلى المعالجة المؤتمتة يعد ضرورة استراتيجية للحد من الأخطاء البشرية القاتلة التي قد تنشأ عند إدخال البيانات أو استرجاعها يدوياً. تشير دراسات النظم وهندسة العمليات إلى أن التدخل اليدوي المتكرر يرفع معدلات الخطأ بنسب طردية مع زيادة حجم البيانات، مما يؤثر سلباً على جودة المخرجات ونزاهة التحليلات. توفر الأتمتة عبر VBA بيئة معيارية ثابتة تطبق القواعد الحسابية والمنطقية بدقة متناهية دون أدنى تذبذب في الأداء، مما يضمن توافق العمليات مع أعلى معايير الجودة المتبعة في نظم المعلومات (Sarker & Sahay, 2003).

علاوة على ذلك، تساهم خوارزميات البحث المؤتمتة في تحسين كفاءة استرجاع السجلات الكبيرة بشكل ملحوظ. فعند التعامل مع آلاف أو مئات الآلاف من الصفوف، تصبح عمليات الفرز والتصفية اليدوية مستهلكة للوقت ومشتتة للموارد المعرفية للمحلل. تسمح لغة VBA بتنفيذ عمليات بحث معقدة وفلترة متزامنة للبيانات بناءً على محددات متعددة في أجزاء من الثانية، مما يمهد الطريق لإجراء دراسات استقصائية وإحصائية معقدة دون الحاجة إلى تصدير البيانات إلى بيئات برمجية خارجية أكثر تعقيداً.

1.2 مقارنة كفاءة الأتمتة البرمجية بالوظائف المدمجة التقليدية

يقارن مستخدمو جداول البيانات عادة بين أداة البحث اليدوية المدمجة في واجهة المستخدم الرسومية، والمتاحة عبر اختصار لوحة المفاتيح الشهير (Ctrl + F)، وبين الأكواد البرمجية المكتوبة بلغة VBA. ورغم أن أداة البحث اليدوية توفر حلاً سريعاً للمستخدم العادي للعثور على قيمة مفردة بصرياً، إلا أنها تفتقر تماماً إلى القدرة على دمج نتائج البحث ضمن تدفق عمل برمجيات أكبر. تتطلب الأداة اليدوية تدخلاً بشرياً مستمراً لتحديد مسار الإجراء التالي لكل نتيجة يتم العثور عليها، مما يجعلها غير صالحة إطلاقاً لبناء أنظمة مؤتمتة أو معالجة الدفعات الكبيرة من البيانات.

من جانب آخر، يعتمد الكثير من المحللين على دوال الصيغ المدمجة في ورقة العمل مثل VLOOKUP وINDEX/MATCH وXLOOKUP لاسترجاع القيم المقابلة بناءً على مفتاح بحث معين. ورغم القوة الحسابية التي تتمتع بها هذه الدوال، إلا أن لها حدوداً تقنية واضحة؛ فهي دوال سكونية تعيد قيماً فقط داخل خلايا محددة، ولا تملك القدرة على تغيير البنية التحتية للمصنف، أو تعديل تنسيقات الخلايا المكتشفة، أو تنفيذ إجراءات شرطية معقدة مثل حذف الصفوف أو نقل السجلات إلى أوراق عمل أخرى. كما أن تكرار هذه الصيغ الحسابية في عشرات الآلاف من الصفوف يؤدي إلى استنزاف هائل لموارد المعالجة وتضخم حجم الملف وبطء عمليات إعادة الحساب التلقائي.

تتفوق الكائنات البرمجية في VBA على دوال الصيغ التقليدية بقدرتها على معالجة الشروط الديناميكية المعقدة وتوفير بيئة تفاعلية مرنة. يتيح الكود البرمجي فحص خصائص الكائن المكتشف، ومعرفة إحداثياته المكانية الدقيقة، وقراءة قيمه وتنسيقاته، ومن ثم اتخاذ قرارات متفرعة برمجياً بناءً على الحالة اللحظية للبيانات. هذا الفصل بين البيانات المجردة وآلية معالجتها يمنح المطورين مرونة فائقة في التحكم بتدفق المعلومات وبناء تطبيقات مكتبية قوية ومستقرة، تشبه إلى حد بعيد النظم الموجهة لحل المسائل المعقدة في البيئات الحاسوبية الحديثة (Waade et al., 2022).

1.3 الأهمية التطبيقية للبحث عن القيم داخل نطاق العمود المفرد

تكتسب استراتيجية حصر نطاق البحث داخل عمود مفرد بدلاً من فحص ورقة العمل بأكملها أهمية كبرى في تحسين الأداء البرمجي وتخفيض زمن التنفيذ. تحتوي ورقة العمل الواحدة في إصدارات إكسيل الحديثة على ما يزيد عن مليون صف وأكثر من 16 ألف عمود، أي ما يعادل مليارات الخلايا المحتملة. إن توجيه خوارزمية البحث للمسح الشامل لجميع هذه الخلايا يمثل هدراً فادحاً لدورات المعالج الدقيقة ويؤدي إلى استجابة بطيئة بشكل ملحوظ. في المقابل، يؤدي تخصيص البحث في عمود محدد، مثل العمود (A)، إلى تقليص الفضاء البحثي بشكل جذري، مما يرفع سرعة الاستجابة إلى مستويات تكاد تكون فورية.

تتعدد الاستخدامات الشائعة للبحث العمودي في البيئات المهنية والأكاديمية، حيث تمثل الأعمدة عادةً حقولاً معيارية محددة النوع في قواعد البيانات الجدولية. ومن أبرز هذه الاستخدامات التحقق من وجود المعرفات الفريدة (IDs)، مثل الأرقام الجامعية للطلاب، وأرقام السجلات المدنية، والرموز الشريطية للمنتجات (Barcodes)، وأكواد المعاملات المصرفية. يضمن البحث في العمود المخصص للمعرفات عدم حدوث تطابقات زائفة قد تنشأ إذا ما تواجدت نفس القيمة الرقمية صدفة في عمود آخر كقيمة نقدية أو تاريخ.

إلى جانب الكفاءة الزمنية، ينعكس حصر البحث في نطاق عمودي محدد إيجاباً على إدارة ذاكرة النظام العشوائية (RAM). عند تنفيذ استعلامات البحث البرمجية، يقوم محرك إكسيل بإنشاء فهارس مؤقتة وتحميل مراجع الخلايا في الذاكرة لفحص خصائصها. تقييد هذه المراجع بعمود واحد يضمن بقاء استهلاك الذاكرة في حدوده الدنيا، مما يمنع حدوث مشاكل تجمد التطبيق (Application Freezing) أو انهيار بيئة التنفيذ، لا سيما عند تشغيل وحدات الماكرو على أجهزة ذات مواصفات عتادية متوسطة أو في بيئات الخوادم الافتراضية المشتركة.

2. البنية التركيبية الأساسية لدالة البحث البرمجية (Range.Find Method)

2.1 التشريح الدلالي لدالة Range.Find

تنتمي دالة Find في بيئة VBA كدالة مدمجة أصيلة إلى فئة كائن النطاق Range ضمن نموذج كائنات إكسيل الأساسي. يتم تطبيق هذه الدالة مباشرة على كائن النطاق المستهدف الذي يمثل خلية واحدة أو مجموعة من الخلايا أو عموداً مكتملاً. من الناحية الوظيفية، تعمل هذه الدالة كمحرك استعلام عالي المستوى يقوم بمسح الذاكرة الحسابية للخلايا المستهدفة للبحث عن نمط بياني محدد، متجاوزة الحاجة إلى بناء هياكل برمجية مخصصة للفرز والمقارنة اليدوية، مما يوفر للمطور أداة معيارية فائقة القوة والأمان.

من أهم الخصائص البنيوية لدالة Range.Find أنها دالة ذات قيمة مرجعية كائنية؛ فهي لا تعيد مجرد قيمة رقمية تدل على رقم الصف أو قيمة نصية تدل على المحتوى، بل تعيد كائناً برمجياً كاملاً من نوع Range يشير تحديداً إلى أول خلية تطابق معايير البحث المحددة. يتيح هذا التصميم للمطور الوصول الفوري إلى كافة الخصائص والوظائف المرتبطة بتلك الخلية المكتشفة، مثل قراءة قيمتها، أو تغيير لون خلفيتها، أو فحص صيغتها، أو حتى استخدامها كنقطة انطلاق لعمليات إزاحة مكانية أخرى داخل ورقة العمل.

في المقابل، يفرض هذا التصميم الكائني دقة خاصة في التعامل مع النتائج السلبية؛ ففي حال فشلت الدالة في العثور على أي خلية تحقق شروط البحث، فإنها لا تعيد قيماً خطئية تقليدية مثل (N/A) أو صفراً، بل تعيد الكائن الخاص Nothing. يمثل هذا الكائن في لغة VBA غياب المرجع الفعلي في الذاكرة، ويتطلب أسلوباً منطقياً معيناً للتحقق من وجوده قبل محاولة استدعاء أي من خصائصه، وذلك لتفادي وقوع أخطاء وقت التشغيل التي توقف تنفيذ الماكرو بالكامل.

2.2 المعاملات الأساسية والاختيارية في بنية الاستدعاء

تمتلك دالة Range.Find تركيبة نحوية غنية تضم معاملاً واحداً إلزامياً ومجموعة من المعاملات الاختيارية التي تحدد سلوك الفحص بدقة متناهية. الصيغة العامة لاستدعاء الدالة تأتي على النحو التالي:

expression.Find(What, After, LookIn, LookAt, SearchOrder, SearchDirection, MatchCase, MatchByte, SearchFormat)

يمثل المعامل What الوسيط الإلزامي الوحيد، وهو يعبر عن القيمة أو البيانات أو السلسلة النصية المراد البحث عنها داخل النطاق المستهدف. أما بقية المعاملات، ورغم تصنيفها البرمجي كمعاملات اختيارية (Optional)، إلا أن ممارسات البرمجة الرصينة تفرض تحديد معظمها بوضوح لتجنب السلوكيات غير المتوقعة للماكرو.

تتضمن المعاملات الاختيارية وسائط بالغة الأهمية مثل LookIn لتحديد طبقة البيانات المفحوصة، وLookAt للتحكم في دقة التطابق، وMatchCase لضبط الحساسية لحالة الأحرف. تتيح لغة VBA استدعاء هذه المعاملات بطريقتين: إما عبر الترتيب الموضعي المجرد (Positional Arguments) بوضع الفواصل في الأماكن الشاغرة، أو عبر استخدام المعاملات المسماة (Named Arguments) باستخدام الرمز := (مثل LookAt:=xlWhole). يعد الأسلوب الأخير هو الأفضل هندسياً وأكاديمياً، حيث يضمن مقروئية عالية للشيفرة المصدرية ويمنع الأخطاء الكارثية الناتجة عن إزاحة ترتيب المعاملات بالخطأ.

2.3 إسناد المتغيرات البرمجية للكائنات المستهدفة

نظراً لأن مخرجات دالة Find هي مراجع لكائنات في الذاكرة وليست أنواع بيانات أولية مثل الأرقام أو النصوص، فإن لغة VBA تفرض استخدام الكلمة المفتاحية Set لربط تلك المخرجات بالمتغيرات المخصصة لها. يمثل المتغير المعرف كـ Range مؤشراً برمجياً يوجه بيئة التشغيل إلى موقع الخلية في ذاكرة التطبيق، وبالتالي فإن محاولة كتابة foundCell = searchRange.Find(...) بدون استخدام Set ستؤدي حتماً إلى إطلاق خطأ فادح في الترجمة أو وقت التشغيل لانتهاك قواعد الإسناد الكائني.

يختلف تخصيص مراجع الكائنات اختلافاً جوهرياً عن تخصيص المتغيرات البسيطة مثل الأعداد الصحيحة والنصوص؛ فالمتغير البسيط يحجز مساحة تخزينية تحتوي القيمة بذاتها، في حين أن متغير الكائن يحتفظ فقط بعنوان الكائن في الذاكرة. يعني هذا أن أي تعديل يتم تطبيقه عبر المتغير (مثل تغيير محتوى الخلية) ينعكس فوراً وبشكل مباشر على ورقة العمل الأصلية، وهو ما يمنح البرمجة الكائنية مرونة استثنائية في إدارة وتحديث السجلات الجدولية المعقدة.

تقتضي الإدارة الاحترافية للذاكرة مراعاة دورة حياة هذه الكائنات وتفريغها عند انتهاء الغرض منها، لا سيما في التطبيقات الضخمة التي تعالج آلاف الحركات التكرارية. رغم أن جامع القمامة التلقائي في VBA يقوم بتحرير المتغيرات المحلية بمجرد انتهاء الإجراء الفرعي، إلا أن الممارسة البرمجية المثلى توصي بتصفية المتغيرات الكائنية صراحة عبر إسناد القيمة Nothing لها (مثل Set foundCell = Nothing)، لضمان استقرار موارد النظام وتفادي تسرب الذاكرة (Memory Leaks) في بيئات العمل الإنتاجية.

3. التحليل التفصيلي لمعاملات دالة البحث في بيئة VBA

3.1 معامل القيمة المستهدفة (What) وأنواع البيانات

يمثل المعامل What المحور الجوهري لعملية البحث، حيث يستقبل القيمة المراد مطابقتها داخل النطاق العمودي. يتميز هذا المعامل بمرونة فائقة في التعامل مع مختلف أنواع البيانات؛ فهو يقبل النصوص المباشرة، والقيم العددية الصحيحة والعشرية، والتواريخ الزمنية، والقيم المنطقية (Boolean). ومع ذلك، تتطلب بعض أنواع البيانات معالجة تحضيرية؛ فالأرقام والتواريخ قد تتأثر بتنسيق العرض المرئي داخل إكسيل، مما يستوجب مراعاة التوافق بين القيمة الخام والقيمة المعروضة كما سيتم تفصيله لاحقاً في محددات الفحص.

تدعم دالة Find استخدام المحارف البديلة (Wildcards) عند التعامل مع السلاسل النصية، مما يمنح المطور قدرات متقدمة في البحث النمطي. يمكن استخدام علامة الاستفهام (?) للتعويض عن محرف فردي واحد أياً كان نوعه، في حين تتيح علامة النجمة (*) التعويض عن أي عدد من المحارف المتتالية بما في ذلك السلاسل الفارغة. على سبيل المثال، البحث عن "C?t" يطابق كلمات مثل "Cat" و"Cot"، بينما البحث عن "Data*" يطابق أي كلمة تبدأ بهذا المقطع بصرف النظر عن نهايتها. وفي حال كانت القيمة المراد البحث عنها تحتوي فعلياً على هذه الرموز كجزء أصيل من النص، يجب استخدام علامة المدة (~) كرمز إفلات يسبق المحرف البديل (مثل "~*") لإلغاء وظيفته الخاصة.

تعد المسافات البادئة واللاحقة في النصوص من أكثر العوامل المسببة لفشل عمليات المطابقة في بيئات الأعمال الواقعية. غالباً ما تحتوي البيانات المستوردة من قواعد بيانات خارجية أو ملفات نصية على مسافات بيضاء غير مرئية تفصل بين المعرفات النصية. يؤدي البحث عن القيمة "Excel" إلى الفشل إذا كانت الخلية تحتوي فعلياً على "Excel " عند تفعيل المطابقة الكاملة. لتفادي هذه المشكلة، ينصح بتنظيف مدخلات البحث والنطاق المستهدف باستخدام دالة التهذيب Trim قبل الشروع في تمرير المعامل إلى دالة البحث البرمجية.

3.2 محدد نطاق الفحص (LookIn) بين الصيغ والقيم

يتحكم المعامل LookIn في تحديد المستوى الطبقي للبيانات الذي ستتوجه إليه خوارزمية الفحص داخل كل خلية، ويأخذ واحداً من ثلاثة ثوابت برمجية رئيسية معرفة مسبقاً في مكتبة إكسيل: xlValues، أو xlFormulas، أو xlComments. يعد هذا المعامل من أخطر المعاملات تأثيراً على نتائج الاستعلامات، حيث يحدد ما إذا كان محرك البحث سيفحص القيمة المحسوبة النهائية للخلية كما تظهر للمستخدم، أم سيفحص النص المصدري المكتوب داخل شريط الصيغة الرياضية.

عند استخدام الثابت xlValues، تبحث الدالة في النتيجة المعروضة للخلية بعد إجراء العمليات الحسابية وتطبيق تنسيقات الأرقام. هذا الثابت ضروري جداً عندما تكون الخلايا المستهدفة مبنية على معادلات رياضية (مثل =SUM(...)) ويراد البحث عن الناتج الرقمي للمعادلة. ومع ذلك، ينطوي هذا الخيار على محذور تقني حرج؛ إذ يفشل البحث إذا كانت الصفوف مخفية في ورقة العمل، حيث إن إكسيل لا يقوم بتحديث أو فحص القيم المرئية xlValues في الخلايا الواقعة ضمن الصفوف أو الأعمدة المخفية، مما يعيد القيمة Nothing حتى وإن كانت القيمة موجودة بالفعل.

في المقابل، يتجه الثابت xlFormulas مباشرة إلى النص الخام الكامن خلف الخلية؛ فهو يبحث داخل كود الصيغة الحسابية ذاته بالإضافة إلى الخلايا التي تحتوي على نصوص وأرقام ثابتة غير معتمدة على معادلات. يتميز xlFormulas بقدرته الفائقة على استخراج البيانات حتى لو كانت الصفوف مخفية، ولكنه يعجز عن العثور على النواتج الحسابية؛ فإذا كانت الخلية تحوي الصيغة =A1+B1 وكان الناتج هو 100، فإن البحث عن 100 باستخدام xlFormulas سيبوء بالفشل لأن الرقم مفقود داخل نص المعادلة. أما الثابت xlComments فيستخدم حصرياً لاستكشاف التعليقات النصية والملاحظات المرفقة بالخلايا، وهو نادر الاستخدام في عمليات مطابقة السجلات العمودية التقليدية.

3.3 دقة المطابقة بواسطة المعامل (LookAt)

يقوم المعامل LookAt بضبط معيار المطابقة النحوية والدلالية بين القيمة المستهدفة ومحتوى خلايا العمود، ويقبل قيمتين رئيسيتين تمثلان ثوابت برمجية محددة: xlWhole للمطابقة الكاملة، وxlPart للمطابقة الجزئية. يمثل هذا التمييز الفارق الجوهري بين البحث عن الكيان المستقل بذاته والبحث عن الأنماط الفرعية المندرجة داخل نصوص أكبر، وله تداعيات حاسمة على دقة وصحة النتائج المستخلصة.

عند اعتماد الثابت xlWhole، تشترط الدالة تطابقاً تاماً بنسبة 100% بين القيمة الممررة في What وكامل محتوى الخلية المفحوصة دون زيادة أو نقصان. هذا الإعداد هو المعيار الذهبي الإلزامي عند التعامل مع المفاتيح المعرفية الفريدة، والأرقام الأكاديمية، والأكواد الوظيفية. فعلى سبيل المثال، إذا كان العمود يحتوي على الأكواد "101" و"1010" و"101A"، فإن استخدام xlWhole للبحث عن "101" سيضمن استرجاع الخلية الأولى فقط، متجاهلاً الخلايا الأخرى التي تمثل كيانات بيانات مختلفة تماماً.

على النقيض من ذلك، يسمح الثابت xlPart بالعثور على القيمة المستهدفة حتى لو كانت مجرد مقطع فرعي يقع ضمن نص أطول داخل الخلية. ورغم فائدة هذا الخيار في عمليات استكشاف النصوص العامة والكلمات المفتاحية، إلا أنه ينطوي على مخاطر برمجية بالغة في إدارة البيانات الحساسة؛ فقد يؤدي تشابه الجذور اللغوية أو الأرقام المتداخلة إلى استرجاع خلايا غير مقصودة مطلقاً. إن استخدام المطابقة الجزئية دون احتراز قد يتسبب في تعديل أو حذف سجلات خاطئة، لذا يجب توخي الحذر الشديد وعدم تفعيله إلا في السياقات الاستعلامية التي تتطلب البحث الاستكشافي المرن.

3.4 حساسية حالة الأحرف والاتجاه بواسطة (MatchCase & SearchFormat)

يوفر المعامل MatchCase تحكماً منطقياً في مدى حساسية خوارزمية البحث لحالة الأحرف اللاتينية، ويأخذ قيمة منطقية (Boolean) إما True أو False. عند ضبطه على القيمة الافتراضية False، تتعامل الدالة مع الأحرف الكبيرة (Uppercase) والصغيرة (Lowercase) بوصفها متطابقة تماماً؛ فالكلمة "Data" ستطابق "DATA" و"data" دون تمييز. أما عند ضبطه على True، تصبح الدالة صارمة في التحقق، ولا تعيد الخلية إلا إذا تطابقت حالة الأحرف تماماً مع المدخل، وهو ما يكتسب أهمية خاصة عند فحص كلمات المرور الحساسة أو الأكواد الاصطلاحية الموحدة دولياً.

من جهة أخرى، يحدد المعامل SearchDirection مسار التقدم في فحص خلايا العمود، ويأخذ إما الثابت xlNext (وهو الاتجاه الافتراضي الذي يتحرك إلى أسفل العمود تلو الآخر) أو xlPrevious الذي يعكس المسار ليتحرك نحو الأعلى انطلاقاً من أسفل النطاق. يلعب هذا المعامل دوراً حاسماً عندما يحتوي العمود على تكرارات متعددة ويراد الوصول المباشر إلى السجل الأحدث زمنياً (الموجود في أسفل العمود عادةً) دون الحاجة للمرور بكافة السجلات القديمة المعلقة في الأعلى.

أما المعامل SearchFormat، فيتيح دمج التنسيقات البصرية كمعيار من معايير البحث. يتم ضبط هذا المعامل بقيمة منطقية، وعند تعيينه إلى True، فإن الدالة تفحص ليس فقط المحتوى النصي أو الرقمي، بل تشترط تطابق الخلية مع خصائص التنسيق المحددة مسبقاً في كائن التطبيق Application.FindFormat، مثل لون تعبئة الخلية، أو نوع الخط، أو كونه عريضاً. يفتح هذا المعامل آفاقاً استثنائية لمراجعة الجداول وتدقيق السجلات المميزة بصرياً بواسطة المستخدمين السابقين.

4. الإعداد البرمجي وتحديد النطاقات للبحث في عمود كامل

4.1 التصريح عن المتغيرات باستخدام تعليمة Dim

تبدأ كتابة الأكواد البرمجية الرصينة في VBA بالإعلان الصريح والمنهجي عن كافة المتغيرات والكائنات المستخدمة، وذلك بالاعتماد على تعليمة التصريح Dim. من الممارسات الأكاديمية والمهنية الصارمة التي لا غنى عنها وضع التعليمة الإجبارية Option Explicit في السطر الأول تماماً من أي وحدة نمطية (Standard Module). تفرض هذه التعليمة على المترجم البرمجي رفض تشغيل أي كود يحتوي على متغيرات غير معلن عنها مسبقاً، مما يمنع حدوث الأخطاء الخفية الناجمة عن الأخطاء الإملائية في كتابة أسماء المتغيرات، والتي قد تستغرق ساعات طويلة من التنقيح لاكتشافها.

يتطلب إعداد كود البحث في العمود تعريف ثلاثة متغيرات أساسية على الأقل بأشكال بيانية دقيقة تضمن كفاءة استغلال الذاكرة. المتغير الأول هو كائن النطاق العام الذي سيشمل العمود المستهدف ويتم تعريفه بصيغة Dim searchRange As Range، والمتغير الثاني هو كائن النطاق الذي سيستقبل النتيجة المرجعة للخلية المطابقة ويصرح عنه بـ Dim foundCell As Range. أما المتغير الثالث فهو المتغير الحامل لقيمة البحث ذاتها، ويتم تعريفه عادة كمتغير نصي Dim searchValue As String، أو كمتغير عام Variant في حال كان نوع البيانات مجهولاً أو متقلباً بين النصوص والأرقام.

إن تحديد أنواع البيانات الصحيحة أثناء التصريح (Strong Typing) يمنع بيئة VBA من إسناد النوع الافتراضي Variant لجميع المتغيرات دون مسوغ. ورغم مرونة النوع Variant، إلا أنه يستهلك حجماً مضاعفاً من الذاكرة (16 بايت على الأقل للمتغير الواحد مقارنة بـ 4 بايت للمتغيرات المؤشرية)، كما يفرض عبئاً حسابياً إضافياً على محرك التنفيذ للتحقق المستمر من نوع البيانات أثناء وقت التشغيل، وهو ما يتعارض تماماً مع مبادئ البرمجة الأكاديمية السليمة.

4.2 تحديد العمود المستهدف وإسناده إلى كائن النطاق

تتيح لغة VBA صياغات برمجية متعددة للإشارة إلى العمود المستهدف وإسناده إلى كائن النطاق Range عبر الكلمة المفتاحية Set. الصياغة الأكثر شيوعاً وقراءة للمطور البشري هي استخدام تسمية الأحرف الأبجدية للأعمدة، مثل كتابة Set searchRange = ActiveSheet.Columns("A:A") أو اختصاراً Columns("A"). توفر هذه الصياغة وضوحاً بيانياً تاماً للعمود المستهدف، مما يسهل عمليات المراجعة البرمجية السريعة والتحقق من صحة الربط.

على الجانب الآخر، توفر الإشارة الرقمية للأعمدة باستخدام البنية Set searchRange = ActiveSheet.Columns(1) مرونة برمجية فائقة عند بناء تطبيقات متقدمة تعتمد على الحلقات التكرارية أو الحسابات الديناميكية لأرقام الأعمدة. يتيح الترقيم الرقمي للأعمدة استبدال الرقم الثابت بمتغير عددي يتغير بناءً على مدخلات المستخدم أو نتائج دوال أخرى، مما يجعل الكود قادراً على التنقل الآلي عبر أعمدة ورقة العمل دون الحاجة لكتابة أكواد مكررة لكل عمود على حدة.

علاوة على ذلك، يمكن تحسين كفاءة استهداف النطاق عن طريق تجنب حجز العمود بالكامل بملايين خلاياه الفارغة، واستبدال ذلك بالتركيز الحصري على النطاق المستخدم فعلياً بواسطة خاصية UsedRange. يتيح الجمع بين تقاطع العمود والنطاق المستخدم، أو استخدام أسلوب حصر الصفوف المتضمنة لبيانات، تحديد نطاق بحثي مركز ينتهي عند آخر خلية مأهولة، وهو ما يضمن سرعة فائقة في المعالجة وتخفيضاً ملموساً في الموارد المخصصة لعمليات الفحص البرمجي.

4.3 ربط النطاق بورقة العمل المحددة وتجنب الإشارات المبهمة

يمثل الاعتماد المطلق على الكائن الافتراضي ActiveSheet أحد أكثر الأخطاء البرمجية شيوعاً وخطورة في بيئة VBA. يشير هذا الكائن إلى ورقة العمل التي تصادف وجودها في واجهة العرض اللحظية للمستخدم عند تشغيل الماكرو. في بيئات الأعمال والمؤسسات متعددة الأوراق، قد يؤدي النقر المفاجئ للمستخدم على ورقة عمل أخرى، أو انطلاق الماكرو عبر مؤقت زمني أثناء تصفح ورقة مغايرة، إلى تطبيق عملية البحث على بيانات غير صحيحة تماماً، مما ينجم عنه قرارات خاطئة أو إتلاف كارثي للبيانات.

لتجنب هذا الإبهام البرمجي، تقتضي القواعد الهندسية الصارمة الإشارة الصريحة (Explicit Referencing) لورقة العمل الحاضنة للبيانات. يمكن تحقيق ذلك بربط النطاق مباشرة بالمصنف والورقة عبر اسمها الظاهري التبويبي، كأن نكتب Set ws = ThisWorkbook.Worksheets("Data")، ومن ثم استدعاء العمود عبر الكائن المعرف Set searchRange = ws.Columns("A"). يضمن هذا الأسلوب استقلالية الكود تماماً عن التفاعلات المرئية للمستخدم، واستمرار تنفيذه بشكل صحيح حتى لو كانت ورقة العمل في الخلفية أو غير مرئية.

بالإضافة إلى ذلك، يفضل المطورون المحترفون استخدام الأسماء الكودية البرمجية (CodeNames) لأوراق العمل، وهي الأسماء المعرفة داخلياً في محرر Visual Basic (مثل Sheet1). تتفوق هذه الطريقة على استخدام الأسماء التبويبية في كونها محصنة ضد التغييرات التي قد يطرقها المستخدمون العاديون على أسماء علامات التبويب من واجهة إكسيل، مما يوفر استقراراً مستداماً للتطبيقات الموزعة ويمنع تعطل الأنظمة نتيجة التعديلات العرضية في تسمية الواجهات.

5. دراسة حالة تطبيقية خطوة بخطوة: البحث وتنسيق الخلايا المطابقة

5.1 إعداد بيئة البيانات الافتراضية للتحليل

لإرساء الفهم النظري على أرضية تطبيقية صلبة، سنفترض وجود سجل بيانات رياضي منظم في ورقة العمل الأولى (Sheet1) من المصنف. يمثل العمود (A) في هذا الجدول أسماء أندية كرة السلة للمحترفين، في حين تمثل الأعمدة المجاورة (B و C و D) أسماء اللاعبين، وأرقام قمصانهم، ومتوسط النقاط المسجلة في الموسم على التوالي. يحتوي هذا الجدول الافتراضي على مئات السجلات التي تتداخل فيها أسماء الفرق نتيجة تكرارها لكل لاعب ينتمي لنفس الفريق، مما يستدعي بناء إجراء برمجي للبحث عن نادٍ محدد وتمييزه بصرياً.

تتمثل القيمة المستهدفة للبحث في هذه الدراسة التطبيقية في السلسلة النصية "Rockets"، والتي تشير إلى اسم أحد الأندية. إن الهدف المنطقي للإجراء ليس فقط التحقق من وجود النادي داخل العمود (A)، بل تحديد موقع الخلية الأولى التي تحوي هذا الاسم بدقة، ثم تطبيق تأثيرات تنسيقية بارزة عليها لإبرازها للمستخدم، مع تجهيز البيئة لاحتمالية عدم وجود النادي أصلاً في حال تم إدخال اسم فريق غير مدرج في البطولة.

قبل الشروع في تنفيذ الكود، يخضع العمود (A) لعملية فحص أولية للتأكد من خلوه من الأخطاء التنسيقية المعرقلة، مثل وجود خلايا مدمجة (Merged Cells) التي تعد من ألد أعداء خوارزميات VBA حيث تتسبب في تشويه مراجع النطاقات وإفساد سلوك الدالة Find. كما يراعى أن البيانات لا تحتوي على مسافات زائدة قد تم إدخالها بطريق السهو أثناء الرصد الميداني للمباريات، لضمان أعلى درجات الدقة التجريبية للتطبيق البرمجي.

5.2 كتابة الشيفرة البرمجية المتكاملة للإجراء الفرعي FindValue

فيما يلي النص البرمجي الكامل للإجراء الفرعي FindValueInColumn، مصاغاً وفق أرقى معايير التوثيق الأكاديمي والبرمجي، ومستوفياً لكافة المتطلبات الهندسية التي تم استعراضها:

Sub FindValueInColumn()
    ' تفعيل الإعلان الصريح المنهجي للمتغيرات داخل الإجراء
    Dim ws As Worksheet
    Dim searchRange As Range
    Dim foundCell As Range
    Dim searchValue As String

    ' ربط المراجع الكائنية بالورقة والعمود المستهدف صراحة
    Set ws = ThisWorkbook.Sheets("Sheet1")
    Set searchRange = ws.Columns("A")
    searchValue = "Rockets"

    ' تنفيذ البحث مع تحديد كافة المعاملات لتجنب وراثة الإعدادات السابقة
    Set foundCell = searchRange.Find( _
        What:=searchValue, _
        LookIn:=xlValues, _
        LookAt:=xlWhole, _
        MatchCase:=False _
    )

    ' التحقق المنطقي من صحة الكائن الناتج وتفادي الأخطاء التشغيلية
    If Not foundCell Is Nothing Then
        ' تطبيق التنسيق التلقائي المباشر على الخلية المكتشفة
        With foundCell.Font
            .Color = vbRed
            .Bold = True
        End With
        MsgBox "تم العثور على القيمة بنجاح في الصف: " & foundCell.Row, vbInformation, "نجاح العملية"
    Else
        MsgBox "عذراً، لم يتم العثور على القيمة المطلوبة في العمود المحدد.", vbExclamation, "فشل البحث"
    End If

    ' تصفية مراجع الكائنات لتحرير الذاكرة النظامية
    Set foundCell = Nothing
    Set searchRange = Nothing
    Set ws = Nothing
End Sub

يعكس هذا البناء المنهجي صرامة البرمجة المؤسسية؛ حيث تضمن استخدام المعاملات المسماة داخل دالة Find مع تحديد قيم واضحة لـ LookIn وLookAt وMatchCase قطع الطريق تماماً على أي تداخل محتمل من إعدادات سابقة قام بها المستخدم عبر واجهة إكسيل التفاعلية. كما يوفر استخدام كتلة With...End With تحسيناً ملحوظاً في سرعة الوصول إلى خصائص الخط التابعة للخلية المكتشفة.

5.3 تنفيذ التنسيق التلقائي للخلايا المطابقة برمجياً

بمجرد نجاح دالة Find في الإشارة إلى الخلية المطابقة، يتيح الكائن foundCell الوصول الفوري إلى شجرة الخصائص التنسيقية الخاصة بها. في المثال السابق، تم استخدام الخاصية foundCell.Font.Color = vbRed لتعديل لون الخط مباشرة إلى اللون الأحمر الصريح، وهو أحد الثوابت اللونية المدمجة في VBA. يمكن أيضاً استخدام الدالة RGB(255, 0, 0) لإتاحة مرونة مطلقة في اختيار الدرجات اللونية وفق الهويات البصرية المؤسسية المعتمدة.

ولتعزيز التمييز البصري، تم تفعيل التنسيق العريض عبر إسناد القيمة المنطقية الحقيقية لخاصية الخط العريض foundCell.Font.Bold = True. علاوة على ذلك، يمكن للمطورين توسيع حزمة التنسيقات لتشمل تغيير لون خلفية الخلية عبر كائن التعبئة الداخلي، كأن نكتب foundCell.Interior.Color = vbYellow لإبراز الخلية بتظليل أصفر ساطع، أو رسم حدود تأطيرية حولها عبر فئة Borders، مما يمنح المستخدم تغذية راجعة بصرية فورية ومريحة للعين.

من الأهمية بمكان الإشارة إلى ضرورة تضمين آليات لإعادة ضبط التنسيقات القديمة في التطبيقات المتكررة. فإذا قام المستخدم بالبحث عن قيمة ثانية بعد تشغيل الماكرو الأول، فإن الخلية القديمة ستظل محتفظة بلونها وتنسيقها البارز، مما قد يتسبب في حدوث التباس بصري. لذا، تتضمن الممارسات المتقدمة إضافة كود تمهيدي في مطلع الإجراء يقوم بمسح التنسيقات الاستثنائية من العمود (مثل searchRange.Font.ColorIndex = xlAutomatic) لضمان بقاء التطابق الأحدث فقط تحت دائرة الضوء.

6. التحقق المنطقي ومعالجة الاستثناءات البرمجية (Error Handling)

6.1 التحقق من الكائنات الفارغة باستخدام الشرط (If cell Is Nothing)

تعد آلية التحقق من الكائنات الفارغة حجر الزاوية في بناء برمجيات مستقرة وقوية بلغة VBA. عندما تخفق دالة Find في مطابقة القيمة المستهدفة، فإنها تقوم بإسناد الكائن الفارغ Nothing إلى المتغير المخصص للنتيجة (مثل foundCell). إذا حاول الكود قراءة أي خاصية مرتبطة بهذا المتغير دون فحص مسبق، مثل استدعاء foundCell.Row أو foundCell.Value، فإن بيئة التشغيل ستتوقف فوراً مطلقة خطأ وقت التشغيل الشهير عالمياً:

“Run-time error ’91’: Object variable or With block variable not set”

لتفادي هذا الانهيار البرمجي المفاجئ، يتم بناء فحص منطقي صارم باستخدام البنية الشرطية: If Not foundCell Is Nothing Then. تعمل هذه العبارة بمثابة صمام أمان حوسبي يتأكد من أن المؤشر البرمجي يشير إلى مساحة فعلية محجوزة في الذاكرة تمثل خلية حقيقية في ورقة العمل. فقط عند تحقق هذا الشرط بنجاح، يتم السماح للكود بالدخول إلى كتلة التعليمات لتعديل الخصائص أو قراءة الإحداثيات، مما يوفر تجربة استخدام انسيابية ومحمية تماماً ضد التوقفات غير المتوقعة.

ينبغي التأكيد على أن فحص Is Nothing هو الأسلوب الصحيح الوحيد لاختبار نجاح أو فشل دالة Find في لغة VBA. لا يجوز إطلاقاً استخدام المقارنات التقليدية المتبعة مع المتغيرات العددية أو النصية، مثل محاولة كتابة If foundCell = "" أو If foundCell = 0؛ فهذه المقارنات تؤدي بذاتها إلى إطلاق الخطأ ’91’ نظراً لأن محرك اللغة يحاول تقييم القيمة الافتراضية لكائن غير موجود أصلاً في حيز الوجود البرمجي.

6.2 استخدام تعليمات إدارة الأخطاء غير المتوقعة

بالإضافة إلى التحقق المنطقي المباشر من مخرجات البحث، تتطلب الأنظمة المؤسسية الضخمة بناء شبكة حماية أوسع لإدارة الأخطاء الاستثنائية التي قد تطرأ لأسباب تشغيلية خارجة عن نطاق الكود ذاته. قد تنشأ هذه الأخطاء نتيجة وجود حماية بكلمة سر على ورقة العمل تمنع تعديل التنسيقات، أو تلف في بنية الملف، أو محاولة استهداف ورقة عمل تم حذفها من قبل مستخدم آخر. يتم توظيف تعليمة اعتراض الأخطاء On Error GoTo لتوجيه مسار التنفيذ إلى معالج أخطاء مخصص بدلاً من إيقاف البرنامج وإظهار شاشات التنقيح المحرجة للمستخدمين.

يتم تصميم هيكل إدارة الأخطاء بوضع التعليمة On Error GoTo ErrorHandler في مقدمة الإجراء الفرعي، ثم عزل كتلة معالجة الأخطاء في نهاية الإجراء باستخدام تعليمة الخروج الآمن Exit Sub. يضمن هذا الترتيب عدم دخول الكود إلى مسار الأخطاء في الظروف الطبيعية. وفي حال وقوع أي استثناء غير محسوب، يقفز التنفيذ مباشرة إلى التسمية المعنونة ErrorHandler: حيث يمكن استخراج رقم الخطأ ووصفه عبر الكائن Err، وعرض رسالة مهذبة للمستخدم تشرح طبيعة المشكلة دون تعريضه للتفاصيل التقنية المعقدة.

تقتضي المنهجية البرمجية الرصينة استعادة النمط الطبيعي لمعالجة الأخطاء بمجرد الانتهاء من العمليات الحساسة عبر استخدام التعليمة On Error GoTo 0. تلغي هذه التعليمة فاعلية معالج الأخطاء المخصص وتعيد النظام إلى الحالة المعيارية التي تكتشف الأخطاء اللاحقة بدقة. كما يمكن في البيئات المتقدمة كتابة روتين فرعي يقوم بتسجيل هذه الأخطاء (Error Logging) مصحوبة بتوقيت حدوثها واسم المستخدم في ملف نصي خارجي أو في ورقة عمل خفية مخصصة للتدقيق والمتابعة البرمجية.

6.3 تصميم نوافذ التنبيه التفاعلية للمستخدم

تمثل واجهات التواصل اللحظي مع المستخدم النهائي عنصراً حيوياً في اكتمال التطبيقات البرمجية المهنية. تتيح دالة إظهار الرسائل MsgBox في VBA إمكانية عرض نتائج البحث وتفاصيل الخلايا المكتشفة بأسلوب تفاعلي منظم يعزز من قابلية الاستخدام وسهولة التحقق من البيانات. يمكن للمطور دمج إحداثيات الخلية المكانية المستخرجة عبر الخصائص foundCell.Address أو foundCell.Row وfoundCell.Column داخل نص الرسالة لتحديد موقع التطابق بوضوح لا لبس فيه.

تتيح مكتبة VBA تخصيص المظهر المرئي لصناديق الرسائل عبر دمج الثوابت البصرية التي تحدد نوع الأيقونة والأزرار المتاحة. عند نجاح البحث، يتم استخدام الثابت vbInformation لعرض أيقونة المعلومات الزرقاء الهادئة التي تشير إلى إتمام المهمة بنجاح. وفي المقابل، عند إخفاق عملية البحث وعدم العثور على القيمة، يتم استدعاء الثابت vbExclamation لعرض أيقونة التحذير الصفراء لتنبيه المستخدم إلى ضرورة مراجعة مدخلات البحث أو التأكد من سلامة البيانات في ورقة العمل.

علاوة على ذلك، يمكن استغلال الخيارات المتقدمة لـ MsgBox لبناء مسارات اتخاذ قرار شرطية؛ كأن يسأل البرنامج المستخدم عند العثور على القيمة: “هل ترغب في الانتقال مباشرة إلى موقع الخلية؟” مع توفير زري (نعم / لا) عبر الثابت vbYesNo. في حال اختار المستخدم الموافقة، يمكن تنفيذ الإجراء البرمجي foundCell.Select أو Application.Goto foundCell, True لنقل التركيز البصري فوراً إلى الخلية المحددة وجعلها في منتصف الشاشة، مما يوفر تجربة تفاعلية ثرية ومريحة للغاية للمدققين والمحللين.

7. آليات البحث المتقدم: استخراج كافة التكرارات داخل العمود

7.1 قصور البحث المفرد والحاجة إلى استخراج جميع السجلات

بطبيعتها الهندسية المعيارية، تتوقف دالة Range.Find عن العمل بمجرد اصطدامها بأول خلية تحقق معايير البحث المحددة، وتعيد مرجع تلك الخلية الفردية فوراً متجاهلة كل ما يليها. في الكثير من السيناريوهات العملية والمؤسسية، يمثل هذا السلوك قصوراً جوهرياً لا يفي بمتطلبات التحليل؛ ففي جداول كشوف المرتبات أو السجلات الأكاديمية أو قيود المبيعات، تتكرر أسماء الموظفين والأقسام والمنتجات عشرات أو مئات المرات داخل العمود الواحد، مما يستوجب حصر ومعالجة كافة السجلات المتطابقة دون استثناء أي منها.

يتطلب تجاوز هذا القصور بناء استراتيجية برمجية متقدمة تدمج خوارزمية البحث الفردي ضمن بنية حلقية متكررة قادرة على استكشاف النطاق خطوة بخطوة. يجب أن تكون هذه الاستراتيجية قادرة على استلام الخلية الأولى كنقطة انطلاق، ثم استئناف مسح ما يليها من خلايا تسلسلياً حتى استنفاد كافة التطابقات الموجودة في كامل العمود. هذه المعالجة الشاملة تمكن المطور من حساب التكرارات الإجمالية، أو تجميع قيم مرتبطة بتلك السجلات، أو تطبيق التنسيقات البصرية على كامل حزمة البيانات المطابقة دفعة واحدة.

إن الانتقال من البحث الفردي إلى البحث المتعدد ينقل التطبيق من مجرد أداة فحص موضعية إلى نظام استعلام واسترجاع متكامل (Information Retrieval System). هذا النموذج يحاكي تماماً بنية الاستعلامات المتقدمة في قواعد البيانات الكبرى (مثل عبارة SELECT * WHERE)، مما يضفي على جداول بيانات إكسيل مرونة وظيفية هائلة تقارب كفاءة محركات قواعد البيانات العلائقية المعقدة.

7.2 التكامل الحلقي باستخدام الدالة FindNext

لتحقيق الاستخراج المتسلسل لكافة التكرارات، توفر لغة VBA الدالة التوأم المصاحبة لدالة البحث وهي FindNext. تأخذ هذه الدالة معاملاً اختيارياً واحداً يمثل الخلية المرجعية التي يجب استئناف الفحص من بعدها، وتقوم بتطبيق نفس المعايير والإعدادات الأصلية التي تم تمريرها مسبقاً لدالة Find الأساسية دون الحاجة لإعادة كتابتها. يسمح هذا التكامل النظيف بالحفاظ على اتساق شروط البحث (مثل xlWhole وLookIn) عبر كافة دورات الفحص المتتالية.

يتم بناء هيكل التكامل عادة بالاعتماد على حلقة التكرار الشرطية Do...Loop. تبدأ الخوارزمية بتنفيذ استدعاء أولي لدالة Find للعثور على النتيجة الأولى، وإذا كانت النتيجة صالحة (وليست Nothing)، يدخل البرنامج في الحلقة التكرارية لمعالجة الخلية وتطبيق الإجراءات المطلوبة عليها، ثم يتم استدعاء searchRange.FindNext(foundCell) للحصول على النتيجة التالية وإعادة إسنادها لنفس المتغير، وتستمر هذه الدورة في الدوران المنتظم طالما ظلت هناك نتائج جديدة يتم اكتشافها.

أثناء هذا الدوران الحلقي، يمكن تنفيذ مصفوفة واسعة من العمليات المعقدة؛ مثل نسخ الصفوف المتطابقة بالكامل ونقلها إلى جدول تجميعي في ورقة عمل مستقلة، أو تعديل قيمة معينة في الأعمدة المجاورة لكل تكرار، أو تخزين مراجع كافة الخلايا في كائن تجميعي عام مثل Union Range ليتم تطبيق تنسيق أو أمر جماعي موحد عليها بعد انتهاء الدوران، مما يعزز كفاءة المعالجة ويقلل زمن التحديث البصري.

7.3 تجنب الحلقات اللانهائية عبر حفظ عنوان المطابقة الأولى

ينطوي استخدام الدالة FindNext على فخ برمجي شهير وشديد الخطورة يقع فيه الكثير من المطورين المبتدئين؛ فعندما تصل الدالة إلى نهاية العمود وتفحص آخر تطابق موجود فيه، فإنها لا تتوقف أو تعيد القيمة Nothing، بل تقوم بالدوران التلقائي (Wrap Around) والعودة مجدداً إلى قمة العمود لتصطدم بالخلية الأولى المطابقة التي بدأت منها الرحلة. إذا لم يتم التعامل مع هذا السلوك الدائري بصرامة، فإن الحلقة التكرارية Do...Loop ستظل تدور إلى ما لا نهاية (Infinite Loop)، مما يؤدي إلى تجمد برنامج إكسيل بالكامل وانهيار الجلسة وفقدان البيانات غير المحفوظة.

يكمن الحل الهندسي الأنيق والآمن لهذه المعضلة في تخزين العنوان المكاني لأول خلية متطابقة في متغير نصي مخصص في مستهل العملية، كأن نكتب firstAddress = foundCell.Address. يمثل هذا العنوان “نقطة ارتكاز” مرجعية يتم فحصها بدقة في نهاية كل دورة تكرارية. يتم صياغة شرط خروج الحلقة الشرطية باستخدام العبارة: Loop While Not foundCell Is Nothing And foundCell.Address <> firstAddress.

بفضل هذا الشرط المزدوج، يستمر الكود في مسح السجلات الجديدة بثقة تامة، وبمجرد أن تدور الدالة FindNext وتعود مجدداً إلى الخلية المكتشفة أولاً، يكتشف الشرط أن العنوان الحالي يتطابق تماماً مع firstAddress، مما يؤدي إلى كسر الحلقة التكرارية فوراً والخروج الآمن منها. يضمن هذا النهج فحص كافة التكرارات في العمود لمرة واحدة فقط وبدقة متناهية، مع تأمين استقرار موارد المعالج وتحرير الذاكرة دون أدنى مخاطرة بحدوث حلقات لانهائية مدمرة.

8. تحسين الأداء البرمجي في جداول البيانات الضخمة

8.1 إدارة موارد التطبيق أثناء عمليات الفحص المكثف

عند تنفيذ عمليات البحث البرمجية والتنسيق الآلي على جداول بيانات عملاقة تضم مئات الآلاف من الصفوف، فإن الوقت المستغرق في التنفيذ قد يرتفع بشكل ملحوظ إذا ما تم ترك بيئة إكسيل تعمل بإعداداتها الافتراضية. يرجع هذا البطء في المقام الأول إلى استهلاك موارد المعالج في مهام غير ضرورية أثناء تشغيل الكود، وعلى رأسها إعادة رسم واجهة الشاشة الرسومية (Screen Redrawing) مع كل حركة أو تنسيق يطرأ على الخلايا، بالإضافة إلى قيام محرك الحسابات بإعادة تقييم كافة المعادلات الحسابية في المصنف فور حدوث أي تغيير.

لتحقيق أقصى درجات السرعة وانسيابية التنفيذ، تقتضي أفضل الممارسات البرمجية تعطيل هذه العمليات الثانوية مؤقتاً في مطلع الكود البرمجي. يتم ذلك عبر استدعاء أوامر التحكم في بيئة التطبيق التالية:

Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False

يؤدي إيقاف تحديث الشاشة إلى منع إكسيل من إهدار دورات المعالجة في التحديثات البصرية اللحظية، بينما يضمن إيقاف الحساب التلقائي تجميد المعادلات الحسابية المعقدة حتى اكتمال معالجة البيانات، في حين يمنع إيقاف الأحداث انطلاق وحدات ماكرو أخرى قد تكون مرتبطة بتغيير الخلايا.

ومع ذلك، تفرض المنهجية الأكاديمية والمهنية الصارمة الالتزام الحتمي بإعادة تشغيل هذه الخصائص وإرجاعها إلى حالتها الأصلية السليمة فور انتهاء الماكرو، وتحديداً في كتلة الإغلاق الآمن أو معالج الأخطاء:

Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True

إن نسيان إعادة تفعيل هذه الخصائص يترك بيئة إكسيل في حالة “عمياء” وغير تفاعلية للمستخدم، حيث ستبدو الجداول وكأنها مجمدة ولا تستجيب للتعديلات اليدوية، مما يؤكد أن الإدارة الواعية لموارد التطبيق هي مسؤولية هندسية كاملة تقع على عاتق كاتب الكود من البداية وحتى النهاية.

8.2 المقارنة الحسابية بين دالة Find والبحث عبر المصفوفات (Arrays)

في الأوساط المتقدمة لمطوري VBA، يثور نقاش مستمر حول المقارنة الأدائية بين استخدام دالة البحث الكائنية Range.Find وبين تفريغ العمود بالكامل داخل مصفوفة ذاكرة داخلية (Variant Array) وفحصها عبر حلقة تكرارية برمجية مجردة. تعتبر دالة Find خياراً فائق الكفاءة والسرعة لأنها مكتوبة بلغة C++ ومجمعة مسبقاً (Compiled) داخل النواة الصلبة لبرنامج إكسيل، مما يجعلها تتفوق بفارق شاسع على الحلقات التكرارية التي تفحص كائنات الخلايا Cells(i, 1) بشكل مباشر على ورقة العمل.

ومع ذلك، عند التعامل مع مجموعات بيانات تتجاوز نصف مليون صف، فإن أسلوب المصفوفات البرمجية قد يحقق في بعض السيناريوهات زمناً حسابياً أسرع بنسبة طفيفة. يعود ذلك إلى أن قراءة نطاق العمود ونقله دفعة واحدة إلى مصفوفة في الذاكرة العشوائية (مثل arrData = searchRange.Value) يلغي تماماً الحاجة إلى التواصل المستمر بين محرك VBA ونموذج كائنات إكسيل (COM Interface Overhead). تتم المقارنة النصية داخل بنية الذاكرة اللحظية للمعالج بسرعة استثنائية، مما يوفر أداءً مبهراً عند إجراء ملايين المقارنات المعقدة.

ورغم هذه السرعة، فإن أسلوب المصفوفات ينطوي على مقايضة هندسية واضحة (Trade-off)؛ فهو يستهلك حيزاً أكبر من الذاكرة العشوائية لاستيعاب حجم البيانات الضخمة، كما يفقد المطور المزايا الكائنية التلقائية التي توفرها دالة Find، مثل الاستكشاف الفوري لتنسيقات الخلايا، أو التعرف التلقائي على طبقات الصيغ والقيم، أو استخدام المحارف البديلة المتقدمة دون الحاجة لكتابة دوال فحص تعبيرات نمطية مخصصة (Regular Expressions). وبالتالي، تظل دالة Range.Find هي الحل المعياري الأكثر توازناً وموثوقية في الغالبية الساحقة من التطبيقات المؤسسية والأكاديمية.

8.3 تقييد نطاق البحث الفعلي لتسريع المعالجة

من الأخطاء الكلاسيكية التي تقوض كفاءة التطبيقات قيام المبرمج باستهداف العمود الكامل كحيز للبحث عبر العبارة Columns("A") دون أدنى تقييد. ورغم أن دالة Find مصممة لتخطي الفراغات بذكاء، إلا أن حجز العمود بأكمله يجبر بيئة التشغيل على وضع حدود افتراضية تشمل 1,048,576 صفاً كاملاً، مما يفرض عبئاً هيكلياً على فهارس البحث المؤقتة، لا سيما في المصنفات المعقدة التي تستهلك بالفعل مساحات شاسعة من الذاكرة.

تتمثل الممارسة البرمجية الرصينة في تقييد نطاق البحث العمودي ليقتصر حصرياً على المسافة الممتدة من الخلية الأولى وحتى آخر صف يحتوي فعلياً على بيانات في ذلك العمود. يتم استخراج رقم الصف الأخير بدقة متناهية باستخدام البنية البرمجية القياسية التي تحاكي القفز السريع من أسفل المصنف إلى أعلى عبر خاصية End(xlUp):

Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Set searchRange = ws.Range("A1:A" & lastRow)

تضمن هذه الصياغة تقليص الفضاء البحثي من أكثر من مليون صف إلى بضعة مئات أو آلاف من الصفوف المأهولة فقط. هذا التحديد الدقيق للنطاق ينعكس فوراً وبشكل جذري على تقليل زمن استجابة خوارزمية البحث وتسريع إرجاع النتائج، كما يمنع حدوث أي نتائج زائفة قد تنشأ عن وجود بيانات تالفة أو نصوص شبحية مهملة في أقصى قاع ورقة العمل، مما يرسخ مبادئ الكفاءة والنزاهة الإحصائية في معالجة البيانات.

9. سيناريوهات تطبيقية موسعة في بيئات الأعمال والمؤسسات

9.1 البحث الديناميكي التفاعلي بناءً على مدخلات المستخدم

في بيئات الأعمال الواقعية، نادراً ما تكون قيم البحث نصوصاً ثابتة ومشفرة بشكل صلب (Hardcoded) داخل الكود البرمجي كما رأينا في الأمثلة التعليمية الأولية؛ بل تتطلب التطبيقات مرونة كاملة تسمح للمستخدم بتحديد معايير البحث لحظياً وفق احتياجاته المتغيرة. يتم تحقيق هذه الديناميكية عبر دمج أدوات التفاعل مثل الدالة المدمجة InputBox، والتي تقوم بتوليد نافذة حوارية منبثقة تطلب من المستخدم كتابة القيمة المراد استكشافها داخل العمود.

يتطلب دمج مدخلات المستخدم بناء منظومة تحقق صارمة (Validation) لضمان اتساق البيانات المدخلة قبل تمريرها لدالة Find. يجب فحص ما إذا كان المستخدم قد ضغط على زر الإلغاء (Cancel)، أو ترك مربع النص فارغاً تماماً وضغط على موافق؛ ففي مثل هذه الحالات يجب إيقاف تنفيذ الإجراء بأمان عبر Exit Sub لمنع البحث عن نصوص فارغة قد تربك خوارزمية التطابق. تضمن هذه المعالجة الأولية حماية التطبيق من السلوكيات البشرية العشوائية وتمنحه استقراراً تشغيلياً عالياً.

وفي الأنظمة المؤسسية الأكثر نضجاً، يتم الارتقاء بواجهة المستخدم من مجرد صناديق إدخال بسيطة إلى تصميم نماذج مستخدم تفاعلية متكاملة (UserForms). تتيح هذه النماذج للموظفين كتابة نصوص البحث مع إمكانية الاختيار عبر قوائم منسدلة (ComboBoxes) تحدد بدقة العمود المراد فحصه، ونوع المطابقة المطلوبة (كاملة أم جزئية)، مع عرض نتائج البحث بشكل جدول أنيق داخل أداة ListBox، مما يحول جدول إكسيل البسيط إلى تطبيق مكتبي متكامل واحترافي يسهل التعامل معه من قبل الكوادر غير التقنية.

9.2 البحث متعدد المعايير واستخراج البيانات المتقاطعة

لا تتوقف فائدة العثور على القيمة في العمود عند حدود معرفة موقعها أو تنسيق خطها فحسب، بل تمتد لتكون جسراً لاستخراج حزمة البيانات المرتبطة بتلك القيمة في الأعمدة المجاورة لنفس السجل. يتحقق هذا التكامل الحوسبي بسلاسة متناهية عبر استخدام الخاصية الجوهرية Offset المرتبطة بكائن النطاق المكتشف foundCell. تتيح هذه الخاصية التحرك بنسب محددة من الصفوف والأعمدة انطلاقاً من إحداثيات الخلية الحالية كمرجع أساسي.

على سبيل المثال، عند البحث في العمود (A) عن رقم هوية عميل معين والعثور على خليته، يمكن قراءة اسم العميل الموجود في العمود المجاور (B) مباشرة عبر كتابة foundCell.Offset(0, 1).Value، وقراءة رصيده المالي الموجود في العمود (C) عبر foundCell.Offset(0, 2).Value. يتيح هذا الربط الأفقي استرجاع كافة السمات والبيانات المتقاطعة الخاصة بالكيان المكتشف بدقة بالغة وبأقل جهد برمجي ممكن، مستغنياً تماماً عن دوال التوفيق والبحث المعقدة في ورقة العمل.

بالإضافة إلى ذلك، يمكن استخدام هذه التقنية لإجراء عمليات التحقق المتقاطع (Cross-Validation) بين جداول متعددة؛ كأن يتم البحث عن كود الموظف في جدول الحضور والانصراف، وبمجرد العثور عليه، يتم التوجه برمجياً إلى جدول الرواتب في ورقة عمل أخرى للتحقق من تطابق المسمى الوظيفي والدرجة المالية. تتيح هذه القدرة الاستعلامية المتقدمة أتمتة عمليات التدقيق والمطابقة المحاسبية الشهرية في المؤسسات المالية الضخمة، مما يوفر مئات الساعات من العمل اليدوي المضني ويقضي تماماً على التناقضات البيانية.

9.3 أتمتة عمليات التحديث والحذف للسجلات المطابقة

يمثل التعديل التلقائي والحذف الممنهج للسجلات القديمة أو التالفة أحد أهم التطبيقات المتقدمة لدالة البحث البرمجية في صيانة وتطهير قواعد البيانات (Data Cleansing). بمجرد استقرار مؤشر البحث على الخلية المطابقة للشروط المستهدفة، يمتلك الكود صلاحية فورية لتحديث محتواها وإعادة كتابة قيم جديدة تتوافق مع معايير التدقيق الحديثة، مثل استبدال الأكواد المنتهية الصلاحية بأكواد بديلة مفعلة بنقرة زر واحدة.

أما في السيناريوهات التي تستلزم تنظيف المصنف من السجلات المكررة أو الملغاة نهائياً، فيمكن إعطاء أمر الحذف للصف بأكمله الذي يحتضن الخلية المكتشفة بالاعتماد على الخاصية foundCell.EntireRow.Delete. ومع ذلك، يفرض تنفيذ هذا الأمر احترازاً برمجياً شديد التعقيد، خاصة إذا كان الحذف يتم داخل حلقة تكرارية متعددة عبر FindNext؛ فحذف الصف المكتشف يؤدي إلى تغيير مراجع وهياكل الصفوف التي تليه فوراً، مما قد يربك مؤشر دالة FindNext ويتسبب في تخطي سجلات أو تكرار مسح خلايا معينة.

لمواجهة هذا التحدي التقني في عمليات الحذف المتعدد، توصي المنهجية الهندسية باتباع أحد أسلوبين: إما تجميع مراجع كافة الصفوف المراد حذفها أولاً داخل كائن نطاق موحد باستخدام الدالة Union، ومن ثم تنفيذ أمر الحذف الجماعي دفعة واحدة بعد انتهاء حلقة البحث بالكامل خارج الـ Loop، أو الاستغناء عن FindNext والاعتماد على الجمع المتناغم بين دالتي البحث والاستبدال الشامل Range.Replace المدمجتين في إكسيل، والتي تنفذ عمليات الاستبدال أو الحذف النصي على كامل العمود بأقصى سرعة ممكنة وبأمان هيكلي تام.

10. أفضل الممارسات البرمجية والأخطاء الشائعة وكيفية تلافيها

10.1 ظاهرة الإعدادات الثابتة المستمرة (Sticky Settings) في أداة البحث

تعتبر ظاهرة “الإعدادات المستمرة” أو ما يصطلح على تسميته تقنياً بـ (Sticky Settings) من أكثر الخصائص السلوكية إرباكاً للمطورين ومصدراً للأخطاء الخفية المستعصية في بيئة VBA. يرجع أصل هذه الظاهرة إلى أن محرك إكسيل يشترك في بنية برمجية واحدة لعمليات البحث؛ فعندما يقوم مستخدم عادي بفتح نافذة البحث اليدوي (Ctrl + F) واختيار البحث في “القيم” بدلاً من “الصيغ”، أو تفعيل خيار “مطابقة حالة الأحرف”، فإن هذه التفضيلات لا تقتصر على تلك الجلسة اليدوية فقط، بل يتم حفظها وتثبيتها تلقائياً في ذاكرة التطبيق المركزية.

المشكلة الكبرى تكمن في أنه إذا تم استدعاء دالة Range.Find في كود VBA مع إغفال التحديد الصريح لأحد المعاملات الاختيارية (مثل إهمال كتابة LookIn أو LookAt)، فإن الماكرو لن يعود إلى قيم افتراضية ثابتة مسبقاً، بل سيرث تلقائياً آخر إعدادات تم تطبيقها في البرنامج، سواء كانت تلك الإعدادات قد حُددت بواسطة ماكرو آخر تم تشغيله سابقاً أو بواسطة تعديل يدوي قام به مستخدم المصنف قبل ثوانٍ معدودة. هذا السلوك يفسر لِم قد يعمل كود برمجى معين بنجاح تام في الصباح، ثم يفشل فجأة ودون أي تعديل على أسطره في المساء لمجرد أن المستخدم أجرى بحثاً يدوياً عارضاً في إكسيل.

لتفادي هذه الكارثة التقنية بصورة قاطعة، تفرض المعايير الصارمة لهندسة برمجيات VBA إلزامية تحديد وتعيين كافة المعاملات الحيوية صراحة (Explicit Parameters) في كل مرة يتم فيها استدعاء دالة Find. يجب دائماً كتابة معاملات LookIn:=xlValues، وLookAt:=xlWhole، وMatchCase:=False دون أي تهاون أو اتكال على الإعدادات التلقائية. هذا الالتزام الصارم يحصن الكود ضد أي تلوث تراكمي ناتج عن وراثة الإعدادات ويضمن تطابقاً وظيفياً ثابتاً ومستقلاً عن أي تفاعلات خارجية للمستخدم عبر الزمن.

10.2 المعايير المنهجية لكتابة أكواد VBA قابلة للصيانة

إن كتابة الكود البرمجي الذي يؤدي وظيفته الحالية بنجاح تمثل نصف المهمة فقط؛ أما النصف الآخر الأكثر أهمية فهو ضمان قابلية هذا الكود للصيانة (Maintainability) والتطوير المستقبلي بواسطة مبرمجين آخرين أو بواسطة المطور نفسه بعد مضي فترات زمنية طويلة. يتطلب تحقيق ذلك تبني معايير منهجية واضحة في تسمية المتغيرات؛ كاستخدام مبادئ اتفاقية التسمية المجرية (Hungarian Notation) أو التسميات الوصفية الدالة التي تعبر بوضوح عن نوع الكائن ودوره (مثل rngSearchColumn بدلاً من الأسماء المبهمة مثل x أو temp).

يعد التنسيق البصري للشيفرة المصدرية حجر الزاوية في مقروئيتها وجودتها. يجب استخدام الإزاحات التراجعية المنظمة (Indentation) بمقدار علامة جدولة واحدة (Tab) داخل كل مستوى من مستويات التحكم البرمجي، مثل الشروط If...End If، والحلقات Do...Loop، وكتل الكائنات With...End With. هذا التنسيق الهرمي يتيح للعين استيعاب التدفق المنطقي للبرنامج فوراً واكتشاف الشروط المفتوحة أو الحلقات غير المنتهية بسهولة بالغة أثناء مراجعة الكود، مما يرفع من جودة التوثيق الأكاديمي والبرمجي.

بالإضافة إلى ذلك، يجب تطبيق مبدأ تجزئة المسؤوليات (Separation of Concerns) عبر تجنب كتابة الإجراءات الطويلة المتضخمة التي تقوم بكافة المهام دفعة واحدة. ينبغي تفكيك المنظومة البرمجية إلى دوال مستقلة صغيرة من نوع Function تختص كل منها بمهمة فرعية واحدة ومحددة، مثل دالة مخصصة للتحقق من صحة المدخلات، ودالة أخرى تنفذ البحث وتسترجع مرجع الخلية، وإجراء فرعي يتولى تنسيق المخرجات وإرسال الإشعارات. هذا التقسيم المعياري لا يسهل الصيانة والتنقيح فحسب، بل يتيح إعادة استخدام نفس الدوال الموثوقة في مشاريع برمجية أخرى دون الحاجة لإعادة كتابتها من الصفر.

10.3 إجراءات الاختبار والتحقق والتدقيق البرمجي

تكتمل دورة حياة التطوير البرمجي بإخضاع الأكواد لاختبارات تدقيقية صارمة وشاملة قبل طرحها للاستخدام الإنتاجي في المؤسسات. توفر بيئة محرر Visual Basic (VBE) ترسانة متميزة من أدوات التنقيح البرمجي (Debugging) التي يجب على كل مطور احتراف استخدامها. يعد مفتاح الوظائف F8 الأداة الأساسية لإجراء التنفيذ المرحلي خطوة بخطوة (Step-Into)، والذي يسمح بمراقبة مسار التنفيذ سطراً بسطر والتأكد من انسيابية الشروط المنطقية كما هو مخطط لها بدقة.

ينبغي أثناء هذا الاختبار المرحلي تسخير نافذة المراقبة اللحظية (Watch Window) لرصد قيم المتغيرات المتغيرة وحالات الكائنات في كل لحظة، وتحديداً مراقبة تحول المتغير من كونه Nothing إلى كائن خلية حقيقي بعد استدعاء دالة Find، بالإضافة إلى متابعة قيم الإحداثيات والخصائص في نافذة المعاينة الفورية (Immediate Window) عبر كتابة أوامر الطباعة السريعة Debug.Print foundCell.Address. يضمن هذا الرصد المجهري استكشاف أي انحرافات منطقية قبل وصول الكود إلى المستخدم النهائي.

أخيراً، يجب اختبار متانة الشيفرة البرمجية تحت وطأة الحالات الحدية والحرجة (Edge Cases) التي تفشل البرمجيات الضعيفة في الصمود أمامها. يشمل ذلك تجربة تشغيل كود البحث على عمود فارغ تماماً، أو البحث عن قيمة غير موجودة مطلقاً في ورقة العمل، أو تمرير سلاسل نصية شديدة الطول تتجاوز الحدود المعتادة، أو اختبار سلوك الكود عند وجود خلايا تحتوي على أخطاء حسابية صريحة مثل #DIV/0! أو #N/A. إن نجاح الكود في تجاوز كافة هذه السيناريوهات الاستثنائية بمرونة وإظهار الإشعارات التوضيحية المناسبة دون أن يتعرض للانهيار هو الدليل الأكيد على جودته الحوسبية وتوافقه مع أرفع المعايير المهنية المتبعة في إدارة وتطوير نظم المعلومات.

المراجع

  • Sarker, S., & Sahay, S. (2003). Understanding Virtual Team Development: An Interpretive Study. Journal of the Association for Information Systems. https://doi.org/10.17705/1jais.00028
  • Waade, P. T., Enevoldsen, K., Vermillet, A.-Q., Simonsen, A., & Fusaroli, R. (2022). Introducing tomsup: Theory of mind simulations using Python. Behavior Research Methods. https://doi.org/10.3758/s13428-022-01827-2
★

تقييم هذا المحتوى

5.0 / 5 • 7 تقييمات

اقتباس هذا المقال

looti, M. (2026, أكتوبر 20). VBA: كيفية العثور على قيمة في عمود (مع مثال). عرب سايكلوجي. https://arabpsychology.com/statistics/vba-how-to-find-value-in-column-with-example/
looti, Mohammed. “VBA: كيفية العثور على قيمة في عمود (مع مثال).” عرب سايكلوجي, 20 أكتوبر 2026, https://arabpsychology.com/statistics/vba-how-to-find-value-in-column-with-example/.
looti, Mohammed. “VBA: كيفية العثور على قيمة في عمود (مع مثال).” عرب سايكلوجي. أكتوبر 20, 2026. https://arabpsychology.com/statistics/vba-how-to-find-value-in-column-with-example/.