تُعد لغة البرمجة Visual Basic for Applications، المعروفة اختصاراً بـ VBA، إحدى الركائز التقنية الأساسية التي طوّرتها شركة مايكروسوفت لأتمتة العمليات ومعالجة البيانات داخل بيئة تطبيقات مكتبية واسعة الانتشار، لا سيما مايكروسوفت إكسيل. ورغم التطور المتسارع في لغات البرمجة الحديثة وظهور أدوات تحليل البيانات المتقدمة، لا تزال لغة VBA تحتفظ بمكانة استثنائية في قطاعات الأعمال والمؤسسات الأكاديمية والمالية؛ نظراً لقدرتها الفائقة على التفاعل المباشر مع واجهات التطبيقات، وتطويع النماذج الجدلية المعقدة، والتحكم الدقيق في مسارات تدفق البيانات النصية والرقمية دون الحاجة إلى بنى تحتية برمجية مستقلة.
في سياق معالجة البيانات النصية، تمثل مطابقة النصوص وفلترتها التحدي الأكبر الذي يواجه المطورين ومحللي النظم. فبينما يسهل التحقق من التطابق التام أو المساواة المباشرة باستخدام المعاملات المنطقية التقليدية، تتطلب معالجة السجلات الواقعية في جداول البيانات مرونة تتجاوز قيود المقارنة الحرفية، من خلال البحث عن الأنماط، واستخراج النصوص الجزئية، واستبعاد المدخلات الشاذة. ويبرز هنا معامل المطابقة Like كأداة قوية تتيح مقارنة النصوص بالاستناد إلى قوالب محددة تتضمن محارف بديلة، مما يمنح المبرمج قدرات شبيهة بالتعبيرات النمطية ولكن بتركيب نحوي مبسط ومتكامل أصلياً مع محرك اللغة.
غير أن متطلبات التحليل البرمجي لا تقتصر على إثبات الوجود والمطابقة، بل تمتد في كثير من السيناريوهات المتقدمة إلى نفي المطابقة والتحقق من عدم اتّباع النصوص لأنماط معينة. يثير مفهوم “NOT LIKE” في VBA العديد من التساؤلات البرمجية، نظراً لغياب معامل ثنائي مدمج يحمل هذا الاسم، بخلاف ما هو مألوف في لغات الاستعلام البنيوية مثل SQL. ومن هنا، تنبثق الحاجة الأكاديمية والعملية إلى تفكيك الآلية المنطقية الصحيحة لدمج المعامل المنطقي Not مع معامل المقارنة Like، وفهم أسبقية العمليات، والتعامل مع المحارف البديلة، وإدارة الأخطاء وحالات الأحرف، وهو ما سيتناوله هذا الدليل الشامل بتفصيل تحليلي وتطبيقي متكامل.
1. مقدمة إلى مطابقة النصوص ومعاملات المقارنة في VBA
1.1 المفهوم النظري لمعامل المطابقة Like ووظيفته البرمجية
يُمثل معامل المطابقة Like في لغة Visual Basic for Applications أداة مقارنة متخصصة صُممت لتقييم مدى تطابق سلسلة نصية معينة مع نمط هيكلي محدد. على النقيض من معامل المساواة التقليدي (=) الذي يفرض تطابقاً كلياً ومتماثلاً بين السلسلتين النصيتين حرفاً بحرف، يعمل معامل Like وفق مفهوم المطابقة النمطية (Pattern Matching)، حيث يسمح للمبرمج بتحديد قواعد مرنة لوصف بنية النص المستهدف، بما يتيح اكتشاف النصوص التي تشترك في سمات شكلية محددة حتى لو اختلفت في محتواها التفصيلي.
تتجلى الأهمية البرمجية لمعامل Like في قدرته على فك شفرات السلاسل النصية المعقدة وغير المتجانسة، مثل أرقام الحسابات، والرموز البريدية، والهياكل التنظيمية للأكواد داخل قواعد بيانات إكسيل. من الناحية التاريخية، رافق هذا المعامل لغة VBA منذ إطلاقها الأول في عام 1993 ضمن إصدار مايكروسوفت إكسيل 5.0 ليحل محل لغة الماكرو القديمة XLM، حيث وفر للمطورين بيئة تشغيلية قادرة على معالجة البيانات بدقة دون اللجوء إلى كتابة دوال نصية فرعية مطولة ومستهلكة للذاكرة.
يرتكز عمل المعامل على إرجاع قيمة منطقية بوليانية (Boolean) تكون إما True في حال توافق النص بالكامل مع النمط الموصوف، أو False في حال وجود أي انحراف عن القالب المحدد. هذه الطبيعة البنائية تجعل من المعامل حجر زاوية في الشروط التفرعية وحلقات التكرار، وتمنحه ميزة هندسية تجعله يتفوق على المقارنات الثنائية الجامدة، ويقدم حلاً وسطاً يجمع بين بساطة التدوين وسرعة المعالجة الحاسوبية.
1.2 الأساس المنطقي لاستخدام المعامل Not في نفي الشروط
يُعد المعامل المنطقي Not معامل نفي أحادي (Unary Operator) وظيفته الأساسية عكس الحالة المنطقية للتعبير الذي يليه؛ فإذا كان التعبير المنطقي ينتج عنه قيمة صائبة (True)، يقوم المعامل بقلبها لتصبح خاطئة (False)، والعكس صحيح. يُشتق هذا السلوك من قواعد الجبر البولياني، حيث يُستخدم النفي لتحديد المجموعات المتممة، أو استبعاد عناصر معينة تقع خارج النطاق المستهدف لعملية المعالجة الحسابية أو المنطقية.
في هندسة البرمجيات، تنبع الجدوى من بناء شروط النفي بدلاً من الشروط الإيجابية المزدوجة من الرغبة في تبسيط تدفق التحكم (Control Flow). فعندما تتطلب المشكلة استبعاد فئة شاذة واحدة من بين عشرات الحالات المقبولة، يصبح التحقق الإيجابي من جميع الحالات الصالحة أمراً غير عملي ويقود إلى كتابة شفرات برمجية متشعبة ومليئة بالتعقيد. يتيح استخدام النفي هنا صياغة شرط مقتضب يستهدف عزل العنصر غير المرغوب فيه بضربة برمجية واحدة.
تكتسب آلية النفي أهمية استثنائية عند اقترانها بمعاملات المقارنة النمطية. فعند نفي نتيجة مطابقة معينة، يستطيع المطور التركيز على البيانات الاستثنائية التي انحرفت عن النمط المعياري المفترض. هذا التحويل المنطقي يوفر حماية للأكواد من الانهيار، ويقلل من تكرار عبارات الشروط الشرطية المتداخلة، مما يرفع من مقروئية الشفرة ويسهل إجراءات الصيانة والتدقيق البرمجي المستقبلي.
1.3 أهمية التحقق من عدم تطابق الأنماط في تنقية البيانات
تشكل تنقية البيانات (Data Cleansing) مرحلة حرجة في دورة حياة معالجة البيانات داخل المؤسسات، حيث تمتلئ السجلات الواردة بالأخطاء الناتجة عن الإدخال البشري اليدوي أو التحويل غير الدقيق بين الأنظمة المعلوماتية. في هذا الإطار، يُعد التحقق من عدم تطابق الأنماط أداة استراتيجية لعزل وتحديد السجلات المعيبة التي لا تتوافق مع المعايير الشكلية الموضوعة مسبقاً، مثل العناوين البريدية الناقصة، أو أرقام الهويات المشوهة.
يسهم استبعاد المدخلات غير المرغوبة أثناء استيراد البيانات الضخمة (Big Data Imports) في تقليص استهلاك موارد المعالجة ووحدات الذاكرة المؤقتة. فعند قراءة مصفوفات خلايا ضخمة في مايكروسوفت إكسيل، يؤدي الفلترة الاستباقية للبيانات غير المتوافقة إلى منع تمرير سلاسل نصية تالفة إلى العمليات الحسابية اللاحقة، مما يمنع حدوث أخطاء التشغيل المفاجئة، ويقلل من زمن المعالجة الإجمالي بمستويات ملحوظة.
تتضمن التطبيقات الواقعية لهذه التقنية استبعاد السجلات التي لا تبدأ بترميز قطاعي محدد، أو تنقية الجداول المالية من الحسابات المؤقتة التي تحتوي على أحرف خاصة غير مسموح بها، أو التحقق من خلو النصوص المدخلة من المقاطع الوصفية التي تشير إلى إلغاء المعاملات مثل كلمات “Void” أو “Cancelled”. إن بناء أنظمة فحص تعتمد على التحقق السلبي من الأنماط يضمن بقاء قواعد البيانات نقية ومطابقة لأعلى معايير الجودة التنظيمية.
2. التركيب النحوي (Syntax) للتعبير Not Like في لغة VBA
2.1 البنية النحوية المعيارية لصياغة شرط If Not … Like
من الأخطاء اللغوية الشائعة التي يقع فيها المبرمجون القادمون من بيئات برمجية أخرى، ولا سيما لغة استعلام البيانات المدعومة في أنظمة إدارة قواعد البيانات، افتراض وجود معامل ثنائي مركب تحت مسمى Like Not أو NOT LIKE. في لغة VBA، لا وجود لمعامل مركب كهذا على الإطلاق، ومحاولة صياغة التعبير بالشكل التالي تؤدي مباشرة إلى خطأ في بناء الجملة (Compile Error: Syntax Error):
' خطأ نحوي فادح يتسبب في توقف المحرر
If TextValue NOT LIKE Pattern Then ...
تفرض لغة VBA ترتيباً نحوياً معيارياً صارماً يبدأ بالكلمة المفتاحية للشرط If، تليها أداة النفي المنطقي Not، ثم السلسلة النصية المراد فحصها، يعقبها معامل المقارنة Like، وأخيراً قالب النمط المحاط بعلامات تنصيص صريحة، مع اختتام العبارة بالكلمة المفتاحية Then. يُفضل أكاديمياً وبرمجياً إحاطة التعبير الخاضع للتقييم بأقواس دائرية لإزالة أي غموض بصري أو نحوي، مما يجعل البنية الصحيحة تظهر كالتالي:
If Not (string_variable Like pattern) Then
' التعليمات البرمجية التي تنفذ في حال عدم التطابق
End If
تُرجع العملية التقييمية لـ (string_variable Like pattern) أولاً قيمة منطقية مبدئية، ثم يتدخل المعامل Not ليقوم بقلب هذه النتيجة. هذا الترتيب النحوي الدقيق يحافظ على سلامة البنية التحتية لمترجم الأكواد في بيئة الفيجوال بيسك ويضمن تفسير الجمل البرمجية وفق المحددات القياسية التي وضعتها شركة مايكروسوفت لمنتجاتها التطويرية.

2.2 ترتيب الأسبقية والعمليات الحسابية والمنطقية (Operator Precedence)
يخضع تنفيذ العبارات في لغة VBA لجدول أسبقية العمليات الصارم، والذي يحدد الترتيب الزمني الذي يعتمده المترجم لفك رموز التعبيرات المعقدة. ضمن هذا السلم الهرمي، تتقدم العمليات الحسابية أولاً (كالضرب والقسمة والجمع)، تليها معاملات الربط النصي (&)، ثم تأتي معاملات المقارنة التي تتضمن كلاً من المساواة (=)، وعدم المساواة (<>)، والأصغر والأكبر، بالإضافة إلى معامل المقارنة النمطية Like. وأخيراً، تأتي المعاملات المنطقية وفي مقدمتها المعامل Not متبوعاً بـ And و Or.
بناءً على هذا التسلسل، فإن معامل المقارنة Like يمتلك أسبقية أعلى من المعامل المنطقي Not. عندما يقرأ محرك التشغيل تعبيراً مثل Not str Like "A*"، فإنه يقوم تلقائياً بتقييم str Like "A*" أولاً، محولاً النتيجة إلى True أو False، ثم يطبق بعد ذلك عملية النفي المنطقي Not على تلك النتيجة. ومع ذلك، فإن الاعتماد الكامل على الأسبقية الضمنية دون استخدام الأقواس يُعد ممارسة غير محبذة في هندسة البرمجيات؛ لأن الأقواس تحسم النية البرمجية بشكل قاطع وتمنع التفسيرات الخاطئة لدى المراجعين البشريين أو عند تعقيد الشروط البرمجية اللاحقة.
يوضح التحليل خطوة بخطوة للعبارة Not (strVar Like "Z#") أن المحرك يقيم أولاً توافق المتغير strVar مع الحرف Z متبوعاً برقم فردي. فإذا كانت القيمة “Z9″، فإن التعبير الداخلي ينتج True. بعد ذلك، يتدخل المعامل الخارجي ليعكس القيمة إلى False، وبالتالي يتجاوز المعالج كتلة التنفيذ التابعة لـ Then، وينتقل إلى مسار Else أو نهاية الجملة الشرطية، مما يوضح الدقة الرياضية في إدارة الأسبقية.
2.3 التعامل مع المتغيرات النصية (String Variables) والخصائص المباشرة للخلايا
عند التعامل مع جداول البيانات في إكسيل، غالباً ما يتم تمرير خصائص خلايا النطاق مباشرة إلى جمل المقارنة. توفر لغة VBA خصائص متعددة لكائنات الخلايا، وأبرزها Range.Value و Range.Text. يكمن الفرق الدقيق بينهما في أن Value تُرجع القيمة الحقيقية المجردة المخزنة في الخلية (سواء كانت نصاً أو رقماً أو تاريخاً)، بينما تُرجع Text السلسلة النصية المرئية بالصيغة التنسيقية الظاهرة أمام المستخدم في ورقة العمل.
لتفادي وقوع خطأ عدم تطابق الأنواع الشائع Run-time error ’13’: Type Mismatch، يتعين على المبرمج التأكد من أن القيمة الممررة إلى معامل Like هي قيمة نصية حقيقية أو يمكن تحويلها ضمنياً إلى نص. إذا كانت الخلية تحتوي على كود خطأ حسابي صادر عن إكسيل (مثل #N/A أو #VALUE!)، فإن محاولة مقارنتها بالمعامل Like عبر الخاصية Value ستؤدي إلى انهيار الماكرو فوراً؛ والسبب أن قيم الأخطاء لا تتحول تلقائياً إلى نصوص داخل بيئة الذاكرة.
تتمثل الممارسة البرمجية الرصينة في تخزين محتوى الخلية داخل متغير نصي مؤقت صريح (Explicit String Variable) من النوع String قبل إجراء الفحص، أو تغليف الاستدعاء بدالة التحويل CStr() بعد التأكد من سلامة الخلية، مع ضرورة إحاطة كافة القوالب النصية الصريحة بعلامات تنصيص مزدوجة قياسية، ومراعاة مضاعفة علامات التنصيص إذا كان النمط نفسه يتطلب تضمين علامة تنصيص كجزء أصيل من المحارف المراد استبعادها.
3. المحارف البديلة (Wildcards) المدعومة واستراتيجيات نفيها
3.1 توظيف رمز النجمة (*) لمطابقة أي عدد من المحارف واستبعاده
يُعد رمز النجمة (*) المحرف البديل الأكثر مرونة وانتشاراً في عمليات مطابقة النصوص عبر لغة VBA، حيث يمتلك القدرة على تمثيل أي عدد صفري أو تعاقبي من المحارف النصية، بدءاً من غياب المحرف تماماً (صفر من المحارف) وحتى سلاسل نصية طويلة غير محدودة الطول. تتيح هذه المرونة صياغة شروط استبعاد دقيقة تعتمد على موقع النمط المراد رفضه داخل السلسلة النصية الكلية.
عند بناء شرط يهدف إلى استبعاد الخلايا التي تحتوي على مقطع نصي فرعي معين أينما ورد، يتم وضع النجمة في بداية النمط ونهايته. على سبيل المثال، فإن التعبير Not (cell.Value Like "*draft*") يتحقق من أن الخلية خالية تماماً من كلمة “draft”، سواء وردت في أول الجملة أو وسطها أو نهايتها. وفي المقابل، إذا أردنا استبعاد النصوص التي لا تبدأ ببادئة معينة، نضع النجمة في النهاية فقط: Not (strCode Like "PRJ-*")، حيث يضمن هذا الشرط التنبيه على أي كود لا يبدأ بالبادئة الرسمية للمشاريع.
تبرز التطبيقات العملية لنفي النجمة في تصفية لواحق الملفات والامتدادات؛ حيث يمكن عزل وتجاوز أي ملف لا ينتهي بامتداد معتمد باستخدام النمط المقلوب Not (fileName Like "*.xlsx"). إن توظيف النجمة مع أداة النفي يسمح بتنقية مجموعات البيانات بكفاءة دون الحاجة إلى التخمين المسبق لعدد الأحرف المحيطة بالنص المستهدف أو تركيبها الهجائي.
3.2 استخدام علامة الاستفهام (?) لتحديد طول النص واستبعاد الخانات الفردية
على العكس من رمز النجمة ذي الطبيعة التوسعية، يؤدي رمز علامة الاستفهام (?) دوراً هيكلياً صارماً في مطابقة النصوص، حيث يطابق محرفاً نصياً واحداً بالضبط في الموضع المحدد دون زيادة أو نقصان. هذا التحديد الدقيق يجعل من علامة الاستفهام المعيار الهندسي الأمثل لضبط الأطوال وتصفية السجلات التي تنحرف عن التوزيع المكاني للأحرف المستهدفة.
تُستخدم علامة الاستفهام لاستبعاد الأكواد ذات الأطوال غير الصحيحة أو تلك التي تفتقر إلى محارف في مواقع حساسة. فمثلاً، إذا كان المعيار المؤسسي يتطلب أن يتكون الرمز الوظيفي من أربعة محارف يبدأ بحرف E، فإن التعبير Not (empID Like "E???") سيعزل فوراً أي مدخل يخالف هذا الطول بالتحديد، كأن يتكون من ثلاثة محارف فقط أو خمسة، أو يبدأ بحرف مغاير، مما يوفر أداة فورية لاكتشاف أخطاء الترقيم الوظيفي الموضعي.
يمكن دمج علامات الاستفهام مع رمز النجمة لتوليد قوالب تحقق متطورة ورفضها عند الحاجة. فعلى سبيل المثال، النمط Not (record Like "??-*") ينفي ويستبعد كل سجل لا يمتلك محرفين أوليين يليهما خط فاصل متبوعاً بأي محتوى إضافي. يضمن هذا المزيج فحص بنية الترويسة مع غض الطرف عن طول ذيل السلسلة النصية، مما يمنح المطور توازناً مثالياً بين الدقة الموضعية والمرونة البنائية للبيانات المدخلة.
3.3 استبعاد الأنماط العددية باستخدام رمز المربع (#)
يوفر معامل Like في لغة VBA محرفاً بدائياً مخصصاً للمطابقة الرقمية الحصرية، وهو رمز المربع (#)، والذي يتطابق بدقة مع أي رقم مفرد يقع في النطاق من 0 إلى 9. يمثل هذا المحرف أداة مثالية لفصل البيانات الأبجدية البحتة عن البيانات الهجينة أو السجلات التي تسربت إليها أرقام حسابية بطريق الخطأ في حقول مخصصة للأسماء والكيانات الوصفية.
يتحقق التعبير الشرطي Not (cell.Value Like "*#*") من أن السلسلة النصية المستهدفة لا تحتوي على أي رقم عشري على الإطلاق في أي جزء من أجزائها. هذا النوع من الشروط يعد حاسماً في مراجعة أسماء العملاء، وتسميات الموردين، والبيانات الجغرافية للمدن والدول؛ حيث يؤدي اكتشاف أي محرف رقمي إلى إطلاق تنبيه يوضح وجود تشويه في جودة السجل المستهدف مما يستدعي الاستبعاد أو المراجعة.
كذلك يُستخدم رمز المربع لفرض هياكل ترقيم محددة ونفي ما دونها؛ فإذا كانت قاعدة البيانات تتطلب تسجيل أرقام تسلسلية على هيئة حرفين متبوعين بثلاثة أرقام، فإن صياغة الشرط Not (serialNum Like "[A-Z][A-Z]###") ستعزل بدقة متناهية أي سجل يحتوي على حروف بدلاً من الأرقام في الخانات الثلاث الأخيرة، مما يحول دون تلوث الحقول الرقمية بقيم تشغيلية معطوبة.
3.4 نفي مجموعات ونطاقات المحارف باستخدام الأقواس المعقوفة [ ]
تفتح الأقواس المعقوفة [ ] آفاقاً واسعة لمطابقة قوائم ونطاقات محددة من المحارف، وتتيح مستويين مختلفين تماماً من النفي: النفي الخارجي عبر المعامل العام Not، والنفي الداخلي الموضعي عبر إدراج علامة التعجب (!) مباشرة بعد القوس المعقوف المفتوح [!charlist]. يستهدف النفي الداخلي محرفاً واحداً في موضع معين شريطة ألا يكون من ضمن القائمة المحددة بين القوسين.
لإيضاح هذا التمايز الجوهري، فإن التعبير str Like "[!0-9]*" يعني أن السلسلة النصية تبدأ بأي محرف ما عدا الأرقام من صفر إلى تسعة، في حين أن التعبير Not (str Like "[0-9]*") يعني نفي أن السلسلة تبدأ برقم، وهما يلتقيان في النتيجة هنا ولكنهما يختلفان في التركيب المنطقي. يبرز التعقيد عند صياغة نطاقات هجائية؛ فالنمط [!A-Z] يطابق أي محرف مفرد لا ينتمي إلى قائمة الحروف اللاتينية الكبيرة، مما يفيد في اكتشاف الرموز غير المتوقعة أو الحروف المكتوبة بلغات أخرى.
تتعاظم القوة التعبيرية عند الدمج المزدوج، كأن نستخدم النفي الخارجي الشامل مع النطاقات الداخلية: Not (docRef Like "[A-Z]##-[!0-9]")، حيث يستبعد هذا الشرط المركب أي وثيقة لا تتطابق مع حرف كبير متبوعاً برقمين، يليهما خط فاصل، ثم محرف نهائي لا يمثل رقماً. هذا التحكم الميكروسكوبي في بنية النصوص يمنح مبرمجي VBA قدرات فحص تضاهي الأدوات المتخصصة دون الخروج من بيئة إكسيل المكتبية.
4. تهيئة بيئة العمل في Excel VBA للتطبيق التجريبي
4.1 إعداد بيئة التطوير المتكاملة وتفعيل الأدوات اللازمة
قبل الشروع في كتابة وتنفيذ الأكواد البرمجية الخاصة بمعاملات المقارنة والنفي، يتعين تهيئة بيئة التطوير المتكاملة الخاصة بلغة الفيجوال بيسك (VBE) المدمجة داخل برنامج مايكروسوفت إكسيل. تبدأ هذه الخطوة بإظهار تبويب المطور (Developer Tab) على الشريط الرئيسي للتطبيق (Ribbon)؛ حيث يتم ذلك بالانتقال إلى خيارات إكسيل (Options)، ثم تخصيص الشريط (Customize Ribbon)، وتفعيل خانة الاختيار المجاورة لتبويب المطور، ليتاح للمستخدم الوصول المباشر إلى واجهات إدارة الماكرو وأدوات التحكم البرمجية.
بمجرد تفعيل التبويب، يمكن فتح محرر الأكواد عبر النقر على زر Visual Basic أو باستخدام الاختصار المرجعي المباشر من لوحة المفاتيح Alt + F11. في هذه المرحلة، يجب ضبط أحد أهم الخيارات البرمجية الصارمة داخل بيئة التطوير، وهو فرض الإعلان المسبق عن المتغيرات. يتم ذلك بالدخول إلى قائمة Tools ثم Options، وفي تبويب Editor يتم تفعيل الخيار Require Variable Declaration. يؤدي هذا الضبط إلى إدراج العبارة المعيارية Option Explicit تلقائياً في مستهل كل وحدة نمطية جديدة، مما يمنع الأخطاء المطبعية في أسماء المتغيرات أثناء كتابة الشروط المعقدة.
أخيراً، يجب الانتباه إلى طبيعة حفظ مصنف العمل المستهدف؛ إذ لا تسمح ملفات إكسيل الافتراضية ذات الامتداد .xlsx بحفظ وتخزين وحدات الماكرو والأكواد البرمجية. يلزم حفظ الملف صراحة بصيغة تدعم الماكرو، مثل مصنف إكسيل المدعوم بالماكرو Excel Macro-Enabled Workbook ذي الامتداد .xlsm، أو بصيغة الملفات الثنائية .xlsb؛ لضمان بقاء الأكواد ووحدات المعالجة محفوظة ومتاحة للاستخدام المستقبلي دون فقدان البيانات البرمجية عند الإغلاق.
4.2 إدراج وتسمية الوحدات النمطية البرمجية (Standard Modules)
تُمثل الوحدات النمطية المعيارية (Standard Modules) الحاويات البرمجية الأساسية التي تستقر فيها الإجراءات الفرعية (Subroutines) والدوال المعرفة من قبل المستخدم (User-Defined Functions). يتم إدراج وحدة نمطية جديدة من خلال واجهة محرر الفيجوال بيسك عبر النقر على قائمة Insert ثم اختيار Module، أو عبر النقر بالزر الأيمن للفأرة على شجرة مجلدات المشروع في نافذة مستكشف المشاريع (Project Explorer) وتحديد مسار الإدراج ذاته.
عقب إدراج الوحدة النمطية، تظهر في نافذة الخصائص (Properties Window) – التي يمكن إظهارها بالضغط على المفتاح F4 – تحت اسم افتراضي مثل Module1. تقتضي أفضل الممارسات الهندسية إعادة تسمية الوحدة النمطية باسم معبر يعكس محتواها الوظيفي بوضوح، مثل modTextFiltering أو modDataValidation. يساهم هذا التنظيم في تسهيل تصفح الأكواد وصيانتها عند نمو حجم المشروع وتعدد ملفاته البرمجية، ويمنع الخلط بين المعالجات النصية والوحدات النمطية الخاصة بالعمليات الحسابية أو التفاعلية.
داخل الوحدة النمطية، ينبغي مراعاة الهيكلة المنطقية لتوزيع الإجراءات؛ حيث تُقسم الوحدة إلى منطقة الترويسة العامة (General Declarations) التي تتضمن توجيهات البيئة مثل Option Explicit و Option Compare، تليها الإجراءات العامة المتاحة لكافة أجزاء المصنف Public Sub، مع إمكانية استخدام الإجراءات الخاصة Private Sub أو Friend لحصر نطاق الوصول داخل الوحدة ذاتها عند الحاجة لحماية بعض الوظائف التحليلية المساندة من الاستدعاء العشوائي الخارجي.
4.3 تصميم نموذج بيانات تجريبي لاختبار التعبير Not Like
لاختبار دقة الشفرات البرمجية وموثوقيتها في استبعاد الأنماط غير المرغوبة، يجب تصميم نموذج بيانات تجريبي متوازن في ورقة العمل الأولى (Sheet1). يتضمن هذا النموذج سيناريوهات نصية متباينة تجمع بين الحالات الإيجابية الخاضعة للاستبعاد، والحالات السلبية التي يجب أن تجتاز الفحص بنجاح، مما يسمح بالتحقق الشامل من استجابة الشرط المنطقي لمختلف تراكيب الكلمات.
يتم تخصيص العمود A ليكون عمود المدخلات النصية، حيث نملأ الخلايا من A2 إلى A10 بمجموعة من النصوص التي يهدف الفحص إلى البحث عن مدى خلوها من المقطع النصي الصغير “hot”. لتغطية جميع الاحتمالات الموضعية، يتم توزيع الكلمة في مواضع مختلفة؛ فمثلاً ندرج في الخلية A2 كلمة “hotdog” (المقطع في البداية)، وفي A3 نص “shotgun” (المقطع في الوسط)، وفي A4 نص “too hot” (المقطع في النهاية)، مع إدراج كلمات بحروف كبيرة مثل “HOTEL” و “PHOTOGRAPH” لاختبار حساسية الأحرف لاحقاً.
في المقابل، يتم ملء الخلايا المتبقية بنصوص خالية تماماً من هذا المقطع، مثل “cold drink” و “warm soup” و “fresh water” و “ice tea”. ويُترك العمود B فارغاً لتسجيل المخرجات البرمجية والنتائج التحليلية الناتجة عن تنفيذ ماكرو التحقق التلقائي، مما يوفر منصة مرئية واضحة لمقارنة النص الأصلي بالحكم البرمجي الصادر عن التعبير الشرطي وتوثيق أداء الخوارزمية خطوة بخطوة.
5. الدليل التطبيقي خطوة بخطوة: بناء ماكرو التحقق من عدم احتواء النص
5.1 التصريح عن المتغيرات وهيكلة الإجراء الفرعي CheckNotLike
تبدأ كتابة الإجراء البرمجي العملي بصياغة الرأس الإجرائي وتحديد اسم معبر ودقيق للمهمة المنفذة. نختار هنا الاسم CheckNotLike مسبوقاً بالكلمة المفتاحية Sub للإشارة إلى أنه إجراء تنفيذي عام. يلي ذلك إعلان صريح ومنضبط عن جميع المتغيرات التي سيتم استهلاكها داخل الذاكرة المؤقتة، مع اختيار الأنواع البيانية الأمثل لكل متغير وفق مبادئ هندسة البرمجيات النظيفة.
نُصرح عن متغير العداد التكراري i من النوع العددي الطويل Long بدلاً من النوع Integer؛ تفادياً لأي احتمالية لحدوث أخطاء طفحان الذاكرة (Overflow Errors) في حال التوسع في حجم البيانات ليتجاوز سقف 32,767 صفاً، وهو الحد الأقصى للأعداد الصحيحة القصيرة في بيئة الفيجوال بيسك. كما نعلن عن كائن ورقة العمل ws من النوع Worksheet لتفادي الاستدعاءات التكرارية لكائن التطبيق العام وتحسين سرعة استجابة المعالج، مع تدعيم الشفرة بتعليقات توضيحية مفصلة تشرح غرض كل جزء برمجي كالتالي:
Sub CheckNotLike()
' فرض التصريح عن المتغيرات مهيأ في ترويسة الوحدة
Dim ws As Worksheet
Dim i As Long
Dim lastRow As Long
Dim targetText As String
' ربط الكائن بورقة العمل النشطة لتقليل استهلاك الموارد
Set ws = ThisWorkbook.Sheets(1)
تضمن هذه التهيكلة الانضباطية عزل مسارات الذاكرة وتنظيم مساحات التخزين العشوائي المؤقت (RAM)، مما يحمي الماكرو من التضارب مع إجراءات أخرى قد تعمل بالتوازي داخل المصنف الواحد، ويوفر بيئة مستقرة للتنفيذ البرمجي المتلاحق للعمليات المنطقية.
5.2 بناء الحلقة التكرارية (Loop) للمرور على خلايا النطاق
للمرور على سجلات البيانات الموزعة عمودياً في ورقة العمل، يتم إنشاء حلقة تكرارية محددة باستخدام الهيكل For...Next. وعلى الرغم من إمكانية استخدام حدود ثابتة للحلقة من الصف 2 إلى الصف 10 لتغطية نموذج البيانات المبدئي، فإن الممارسة البرمجية الاحترافية تقتضي احتساب الصف الأخير الذي يحتوي على بيانات بصورة ديناميكية كاملة لضمان قدرة الماكرو على العمل مع أي حجم من السجلات دون تعديل يدوي في الأكواد.
يتم استخراج الصف الأخير النشط بالاعتماد على التابع الموثوق End(xlUp) انطلاقاً من أسفل نطاق في العمود A، وهو ما يماثل الضغط اليدوي على الاختصار Ctrl + Arrow Down داخل واجهة إكسيل. يحمي هذا الأسلوب الحلقة التكرارية من التوقف المبكر في حال وجود خلايا فارغة بين السجلات، ويضمن معالجة كافة الصفوف المتاحة بدقة، كما هو موضح في البناء التالي:
' تحديد الصف الأخير المأهول بالبيانات في العمود A ديناميكياً
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
' بدء الحلقة التكرارية من الصف الثاني لتجاوز الترويسة
For i = 2 To lastRow
' استخراج محتوى الخلية وتجريده من الشوائب الأولية
targetText = ws.Cells(i, "A").Value
تُغلق الحلقة التكرارية في نهاية الإجراء باستخدام العبارة Next i مع تحديد متغير الفهرسة الصريح لزيادة المقروئية البصرية للكود ومساعدة المترجم على تنظيم مصفوفة التكرارات بسلاسة وتفادي الحلقات اللانهائية غير المقصودة.
5.3 صياغة الشرط المنطقي وإخراج النتائج في العمود المقابل
يُمثل قلب الإجراء الفرعي في تطبيق الجملة الشرطية التفرعية التي تحتوي على التركيب المنطقي Not … Like لفحص المتغير النصي المستخرج من الخلية. يتم صياغة الشرط للتحقق من عدم احتواء النص على الكلمة الفرعية “hot” محاطة بنجمتين لتمثيل التواجد في أي موضع. فإذا تحقق النفي (أي أن النص لا يحتوي إطلاقاً على هذا المقطع)، يتم توجيه مسار التنفيذ لكتابة القيمة “Does Not Contain hot” في الخلية المقابلة بالعمود B.
في المقابل، إذا فشل النفي (بمعنى أن النص يحتوي بالفعل على المقطع المطلوب استبعاده)، يتولى التفريع Else التعامل مع الحالة المعاكسة ويكتب “Contains hot” في الخلية المقابلة. يُختتم الهيكل الشرطي بالعبارة End If، مما يضمن تدفقاً ثنائياً واضحاً للقرارات المنطقية لكل سجل يمر عبر الحلقة التكرارية، كما يتجلى في المقطع البرمجي التالي:
' تقييم عدم احتواء الخلية على المقطع النصي المحدد
If Not (targetText Like "*hot*") Then
ws.Cells(i, "B").Value = "Does Not Contain hot"
Else
ws.Cells(i, "B").Value = "Contains hot"
End If
Next i
MsgBox "تمت معالجة البيانات بنجاح!", vbInformation, "اكتمال الفحص"
End Sub
عند تنفيذ هذا الإجراء عبر الضغط على المفتاح F5 داخل المحرر، سيلاحظ المطور فوراً أن العمود B قد امتلأ بالتوصيفات المناسبة، حيث تُعامل الكلمات “cold drink” و “warm soup” كبيانات لا تحتوي على المقطع، بينما تُصنف “hotdog” و “shotgun” و “too hot” كمدخلات محتوية عليه، مما يؤكد سلامة البناء المنطقي للتعبير الشرطي المركب.

6. تأثير إعدادات حساسية حالة الأحرف (Case Sensitivity) وتوجيه Option Compare
6.1 المقارنة الثنائية الافتراضية (Option Compare Binary) وسلوك التمييز
تعتمد بيئة لغة VBA بصورة افتراضية نمط المقارنة الثنائية (Binary Comparison) ما لم يُنص صراحة على خلاف ذلك في ترويسة الوحدة النمطية. في هذا النمط الافتراضي، يتم تقييم النصوص بالاستناد الصارم إلى القيم الرقمية لرموز جدول ASCII أو نظام الترميز الموحد الثنائي. ونظراً لأن الحرف الكبير “H” يحمل القيمة الثنائية 72 بينما يحمل الحرف الصغير “h” القيمة 104، فإن محرك المقارنة يتعامل معهما ككيانين مختلفين تماماً لا صلة بينهما.
يقود هذا السلوك الثنائي إلى نتائج قد تفاجئ المطورين عند تطبيق شرط النفي؛ فعلى سبيل المثال، التعبير Not ("HOTEL" Like "*hot*") سيُرجع القيمة True؛ والسبب أن كلمة “HOTEL” المكتوبة بحروف كبيرة لا تتطابق برمجياً مع النمط الصغير “*hot*”. ونتيجة لذلك، يرى المعالج أن النص “لا يحتوي” على المقطع المطلوب، مما يؤدي إلى فشل عملية الاستبعاد وتمرير سجلات كان يُفترض تصفيتها، وهو ما يشكل خطأً منطقياً دقيقاً في مرحلة تنقية البيانات.
تتفاقم هذه الإشكالية في التطبيقات الدولية ومتعددة اللغات، أو عند التعامل مع أسماء النطاقات والبريد الإلكتروني التي يدخلها المستخدمون بحالات أحرف عشوائية. لذلك، فإن الاعتماد على الإعداد الافتراضي دون وعي بطبيعته الحساسة لحالة الأحرف يهدد مصداقية النتائج الإحصائية، ويستوجب التدخل البرمجي لإعادة ضبط سلوك المقارنة على مستوى الوحدة أو المعالجة الفردية.
6.2 تطبيق المقارنة النصية غير الحساسة (Option Compare Text)
للتغلب على قيود المقارنة الثنائية وجعل عمليات الفحص النمطي تتجاهل الفروق بين الأحرف الكبيرة والصغيرة، توفر لغة VBA التوجيه المعياري Option Compare Text. يوضع هذا السطر البرمجي في السطر الأول من الوحدة النمطية، وتحديداً في منطقة التصريحات العامة وقبل أي إجراء فرعي أو دالة مخصصة، حيث يقوم بتحويل نظام المقارنة في الوحدة النمطية بالكامل إلى مقارنة نصية أبجدية غير حساسة لحالة الأحرف (Case-Insensitive).
عند تفعيل هذا الخيار، يستند المحرك إلى الترتيب الهجائي الحرفي المعرّف في الإعدادات الإقليمية لنظام التشغيل ويندوز، فيصبح الحرف “A” مكافئاً تماماً للحرف “a”، والحرف “H” مطابقاً للحرف “h”. بموجب هذا التعديل، فإن الشرط Not (cell.Value Like "*hot*") سيقوم بنجاح باستبعاد كل من “hotdog” و “HOTEL” و “PHoToGraph” دون أي تمييز، معتبراً أن جميع هذه التباينات الشكلية تُمثل النمط ذاته المراد رفضه.
ومع ذلك، ينبغي ممارسة الحذر الهندسي عند إدراج Option Compare Text في المشروعات البرمجية الكبيرة؛ إذ إن تأثيره يمتد إلى كافة دوال المقارنة الأخرى داخل الوحدة النمطية (مثل معاملات المساواة ودوال البحث StrComp). إذا كانت هناك إجراءات أخرى في نفس الوحدة تتطلب فحصاً صارماً لكلمات المرور أو الرموز الحساسة لحالة الأحرف، فإن تعميم هذا التوجيه قد يتسبب في آثار جانبية غير مرغوبة، مما يدفع المطورين للبحث عن حلول بديلة محصورة في مواضع الفحص المحددة.
6.3 استخدام دوال التحويل النصي (UCase و LCase) كحلول بديلة موضعية
تُمثل الاستعانة بدوال التحويل النصي القياسية مثل UCase (للتحويل إلى أحرف كبيرة) و LCase (للتحويل إلى أحرف صغيرة) البديل الهندسي الأكثر أماناً واستقراراً لتوحيد سلوك المقارنة دون التأثير على الإعدادات العامة للوحدة النمطية. بموجب هذه الاستراتيجية الموضعية، يتم تحويل كل من السلسلة النصية المراد فحصها ونمط البحث ذاته إلى حالة موحدة ومطابقة قبل إخضاعهما لمعامل المقارنة.
تتم صياغة الشرط البرمجي في هذه الحالة عبر تحويل القيمة المستهدفة إلى أحرف كبيرة بالكامل ومقارنتها بنمط مكتوب صراحة بأحرف كبيرة كالتالي:
If Not (UCase(ws.Cells(i, "A").Value) Like "*HOT*") Then
' ينفذ هذا المسار فقط إذا كان النص خالياً تماماً من المقطع بشتى حالاته
ws.Cells(i, "B").Value = "Valid Entry"
End If
تتميز هذه التقنية بضمان استقلالية الكود التامة؛ فالشفرة البرمجية ستعمل بنفس الدقة المتطابقة بغض النظر عما إذا كانت الوحدة النمطية تعمل تحت إعداد Option Compare Binary أو Option Compare Text، أو حتى إذا تم نسخ الإجراء الفرعي ونقله إلى ملف عمل خارجي جديد لم يتم ضبط إعداداته مسبقاً. ورغم أن هذا التحويل يضيف عبئاً حسابياً دقيقاً للغاية لاستدعاء دالة التحويل في كل دورة تكرارية، فإن هذا الأثر لا يكاد يُذكر في مجموعات البيانات المعتادة، ويُعتبر ثمناً زهيداً مقابل ضمان الحصانة المنطقية والتوافقية البرمجية الشاملة.
7. سيناريوهات متقدمة: دمج شروط Not Like المتعددة والمعقدة
7.1 الدمج المنطقي باستخدام معاملي And و Or لنفي أنماط متعددة
في التطبيقات الواقعية لتنقية البيانات، نادراً ما يقتصر متطلب الفحص على استبعاد نمط وحيد؛ بل تمتد المتطلبات إلى تصفية السجلات التي تحتوي على أي نمط من قائمة تضم عدة أنماط محظورة. يفرض هذا السيناريو فهماً رياضياً دقيقاً لقوانين المنطق البولياني، ولا سيما قوانين دي مورغان (De Morgan’s Laws)؛ لتفادي الأخطاء المنطقية الكارثية التي تقع عند الخلط بين المعاملين المنطقيين And و Or أثناء النفي.
إذا أردنا التحقق من أن السلسلة النصية لا تحتوي على الكلمة “test” وكذلك لا تحتوي على الكلمة “demo”، فإن الصياغة المنطقية الصحيحة تقتضي استخدام المعامل المنطقي And للربط بين شرطي النفي المستقلين، بحيث يشترط تحقق كلا النفيين معاً لقبول السجل:
If (Not strData Like "*test*") And (Not strData Like "*demo*") Then
' لا يحتوي النص على 'test' ولا يحتوي على 'demo'
ProcessData strData
End If
من الأخطاء الكلاسيكية الشائعة كتابة الشرط بالصيغة: If Not (strData Like "*test*" And strData Like "*demo*") Then؛ حيث يؤدي هذا التركيب الخاطئ إلى قبول أي نص يحتوي على إحدى الكلمتين فقط دون الأخرى، ولا يرفض إلا النصوص التي تجمع بين الكلمتين معاً في آن واحد. ولصياغة النفي الشامل باستخدام المعامل Or، يجب وضعه داخل قوس موحد ينفي اجتماع أي من النمطين: If Not (strData Like "*test*" Or strData Like "*demo*") Then، وهي الصيغة المكافئة تماماً للصيغة المنفصلة السابقة وفقاً لقواعد دي مورغان المنطقية.
7.2 بناء أنماط استبعاد تكرارية باستخدام المصفوفات والوظائف الديناميكية
عندما تتسع قائمة الأنماط غير المرغوب فيها لتشمل عشرات الكلمات أو المعايير الهيكلية، يصبح دمج الشروط بواسطة معاملي And و Or في سطر برمجي واحد أمراً غير عملي ويقود إلى شفرة غير قابلة للصيانة. يتمثل الحل الهندسي المتقدم في هيكلة الأنماط المرفوضة داخل مصفوفة نصية ديناميكية، ثم المرور عليها تكرارياً عبر حلقة فحص متخصصة.
يمكن تحويل هذا النمط التحليلي إلى دالة مخصصة (UDF) قابلة للاستدعاء داخل شفرات الماكرو الأخرى أو حتى في معادلات ورقة العمل المباشرة، كما يتضح من البناء التالي:
Public Function MatchesNoPatterns(ByVal text As String, ByRef patterns() As String) As Boolean
Dim i As Long
' افتراض أولي بأن النص لا يطابق أي نمط مستبعد
MatchesNoPatterns = True
For i = LBound(patterns) To UBound(patterns)
If text Like patterns(i) Then
' بمجرد مطابقة أي نمط محظور، تسقط الصفة ويتم الخروج الفوري
MatchesNoPatterns = False
Exit Function
End If
Next i
End Function
تتيح هذه الدالة للمطور تعريف قائمة الأنماط المحظورة مسبقاً وتمريرها إليها بسهولة، كما في الكود التالي:
Dim ExcludedPatterns() As String
ExcludedPatterns = Split("*temp*,*draft*,*void*,*#*", ",")
If MatchesNoPatterns(cellValue, ExcludedPatterns) Then
' تنفيذ العمليات على السجل السليم والمعتمد
End If
يقدم هذا الأسلوب ميزة الخروج المبكر السريع (Early Exit) عبر التعليمة Exit Function بمجرد العثور على أول نمط محظور، مما يوفر دورات المعالجة الحاسوبية ويمنع استهلاك الوقت في اختبار باقي الأنماط لنص ثبت عدم صلاحيته منذ البداية.
7.3 معالجة النصوص المحتوية على محارف خاصة ومسافات بيضاء
تواجه عمليات مطابقة النصوص واستبعادها عقبات حقيقية عندما تتضمن السلاسل النصية مسافات بيضاء غير مرئية أو محارف خاصة تشترك في رسمها مع الرموز المحجوزة لمعامل Like ذاته (كالنجمة وعلامة الاستفهام والمربع والأقواس المعقوفة). تتسبب المسافات البادئة واللاحقة في إفساد المقارنات المكانية؛ ولذلك يتعين دائماً تنظيف النص المستهدف بتمريره عبر دالة Trim() قبل إجراء المقارنة لضمان استبعاد المسافات الطفيلية التي قد تمنع النمط من الإمساك بالسلسلة النصية بدقة.
أما في حال الرغبة في البحث عن الرموز الخاصة ذاتها لاستبعاد النصوص التي تحتوي عليها، فلا يمكن استخدام الرمز مباشرة في قالب النمط؛ لأن المحرك سيفسره كمحرف بديل وليس كمحرف حرفي. وضعت شركة مايكروسوفت قاعدة صريحة للتعامل مع هذا الموقف تتمثل في إحاطة المحرف الخاص بقوسين معقوفين [*] أو [?] أو [#] أو [[]. على سبيل المثال، إذا أردنا التحقق من أن السلسلة النصية لا تحتوي على علامة النجمة كرمز حقيقي، نكتب النمط كالتالي:
' التحقق من خلو النص من رمز النجمة الفعلي
If Not (rawString Like "*[*]*") Then
' النص لا يحتوي على علامة النجمة
End If
كما تمتد المعالجة المتقدمة للتعامل مع النصوص متعددة الأسطر التي تتضمن فواصل أسطر مدمجة مثل vbCrLf أو vbLf. في هذه الحالات، لا تستطيع المحارف البديلة مثل علامة الاستفهام تجاوز فاصل السطر باعتباره محرفاً عادياً في بعض إصدارات بيئة التشغيل، مما يستوجب استبدال فواصل الأسطر بمسافات عادية عبر دالة Replace(rawString, vbCrLf, " ") كإجراء تطهيري يسبق إخضاع السلسلة لمعامل الفحص النمطي.
8. إدارة الأخطاء وحالات القيم الفارغة (Null و Empty Strings)
8.1 سلوك المعامل Not Like عند التعامل مع القيم الفارغة (Empty Cells)
يتباين السلوك البرمجي لمعامل Like عند التعامل مع الحالات المختلفة لغياب البيانات في بيئة VBA، ولا سيما التمييز الدقيق بين الخلية الفارغة غير المهيأة Empty، والسلسلة النصية الصفرية الطول vbNullString أو ""، والقيمة المنعدمة المنطقية Null التي تظهر غالباً عند التعامل مع حقول قواعد البيانات المرتبطة عبر مكتبات ADO أو DAO.
إذا كانت الخلية المستهدفة فارغة تماماً (Empty)، فإن VBA تقوم ضمنياً بتحويلها إلى سلسلة نصية فارغة "" عند تقييمها بواسطة معامل Like. فإذا كان النمط المستهدف هو "*hot*"، فإن التعبير Empty Like "*hot*" سينتج عنه False، ومن ثم فإن المعامل Not سيقلب القيمة لتصبح True. يقود هذا السلوك الافتراضي إلى اعتبار الخلايا الفارغة مدخلات صحيحة تطابق شرط “عدم الاحتواء على المقطع”، وهو ما قد لا يكون مقصوداً من الناحية التشغيلية؛ إذ قد يرغب المطور في استبعاد الخلايا الفارغة من التقرير أيضاً.
أما إذا كانت القيمة المختبرة تحمل الحالة المنطقية Null، فإن أي عملية مقارنة أو نفي تُجرى عليها ستُرجع حتماً القيمة Null، ولن يتحقق شرط If ... Then أبداً لأن النتيجة ليست True. لتفادي هذه الانحرافات، تنص أفضل الممارسات على تضمين فحص أولي للتحقق من وجود محتوى حقيقي داخل الخلية قبل تطبيق معامل النفي، باستخدام دوال مثل Len() أو IsEmpty():
If Not IsEmpty(cell.Value) And Len(Trim(cell.Value)) > 0 Then
If Not (cell.Value Like "*hot*") Then
' معالجة الخلايا التي تمتلك بيانات فعلية ولا تحتوي على النمط
End If
End If
8.2 معالجة قيم الخطأ الصادرة من معادلات الإكسيل (Excel Errors)
تمثل الأخطاء الحسابية في خلايا إكسيل (مثل #N/A و #VALUE! و #REF! و #DIV/0!) المصدر الأول لانهيار وحدات الماكرو وتوقفها المفاجئ عن العمل عبر إطلاق الخطأ التنفيذي الشهير Run-time error ’13’: Type Mismatch. يعود السبب الجذري لهذا الانهيار إلى أن هذه الخلايا لا تخزن قيماً نصية أو رقمية قياسية، بل تخزن نوعاً بيانياً خاصاً يُعرف بـ CVErr الداخلي لبيئة إكسيل، وهو نوع يرفض محرك VBA تحويله تلقائياً إلى سلسلة نصية عند تمريره لمعامل Like.
لمنع هذه الانهيارات البرمجية وحماية تدفق الكود، تفرض القواعد الهندسية تطويق استدعاء قيم الخلايا بالدالة التحققية IsError(). إذا أرجعت الدالة قيمة True، فهذا يعني أن الخلية تحتوي على معادلة فاشلة حسابياً، ويتعين تجاوزها فوراً أو تسجيل إحداثياتها في سجل خاص بالخلايا المعطوبة بدلاً من محاولة فحصها نصياً، كما يوضح المقطع البرمجي التالي:
If IsError(ws.Cells(i, "A").Value) Then
' تسجيل الخلية المعطوبة والقفز إلى التكرار التالي لتفادي الانهيار
ws.Cells(i, "B").Value = "Cell Contains Excel Formula Error"
Else
' الآن يمكن إجراء الفحص بأمان تام
If Not (ws.Cells(i, "A").Value Like "*hot*") Then
ws.Cells(i, "B").Value = "Valid"
End If
End If
يضمن هذا النهج الدفاعي في كتابة الشفرات مناعة الماكرو ضد البيانات غير المنضبطة، ويحول دون توقف المعالجة في الملفات الضخمة التي قد تحتوي على معادلات معطلة لا تقع تحت سيطرة المبرمج المباشرة.
8.3 تطبيق المعالجة الشاملة للأخطاء البرمجية (On Error Handling)
لا تكتمل المنظومة البرمجية الموجهة لبيئات العمل الاحترافية دون دمج هيكل شامل لمعالجة الأخطاء الاستثنائية غير المتوقعة (Global Error Handling) باستخدام تعليمة On Error GoTo. تتيح هذه التعليمة التقاط أي خلل تشغيلي يطرأ أثناء تقييم السلاسل النصية أو التعامل مع مصفوفات الخلايا، وتوجيه مسار التنفيذ إلى كتلة تنظيفية مخصصة تحول دون تجميد التطبيق أو ترك خصائص إكسيل في حالة غير مستقرة.
تكمن الأهمية القصوى لكتلة معالجة الأخطاء في قدرتها على إعادة تفعيل خصائص النظام الحساسة، مثل تحديث الشاشة ScreenUpdating ونمط الحساب التلقائي Calculation، والتي يتم تعطيلها عادة في مستهل الإجراءات لتحسين السرعة. فإذا وقع خطأ أثناء عمل حلقة Not ... Like دون وجود معالج أخطاء، سيظل التطبيق متجمداً ولن يرى المستخدم أي استجابة مرئية من إكسيل، مما يوحي بحدوث عطل دائم في البرنامج.
تتم هيكلة المعالج الاحترافي وفق النمط التالي:
Sub SafeNotLikeExecution()
On Error GoTo ErrorHandler
' إيقاف تحديثات التطبيق لرفع كفاءة المعالجة
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' --- التعليمات البرمجية الأساسية وحلقات الفحص ---
CleanExit:
' إعادة ضبط إعدادات النظام الحيوية قبل الخروج الطبيعي
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Exit Sub
ErrorHandler:
' توثيق الخطأ وتقديم رسالة واضحة للمستخدم
MsgBox "حدث خطأ تنفيذي رقم: " & Err.Number & vbCrLf & _
"الوصف: " & Err.Description, vbCritical, "خطأ في المعالجة"
Resume CleanExit
End Sub
توفر هذه الهيكلية أقصى درجات الموثوقية الهندسية، حيث تضمن استعادة التطبيق لكامل وظائفه الطبيعية فور خروج الإجراء، سواء اكتملت المعالجة بنجاح تام أو واجهت عائقاً غير متوقع في جودة البيانات المدخلة.
9. مقارنة الأداء والبدائل البرمجية لمعامل Not Like
9.1 المقارنة بين Not Like ودالة البحث النصي InStr
تُعد دالة البحث النصي الصريح InStr البديل الكلاسيكي الأكثر استخداماً للتحقق من عدم احتواء النصوص على مقاطع فرعية معينة. تعمل هذه الدالة على إرجاع الموضع الرقمي لأول ظهور للمقطع النصي المطلوب داخل السلسلة المستهدفة؛ فإذا لم يظهر المقطع إطلاقاً، تُرجع الدالة القيمة الصفرية 0. وبناءً على ذلك، تتم صياغة شرط النفي عبر الدالة بالشكل: InStr(1, SourceText, "hot", vbTextCompare) = 0.
من منظور الأداء الحاسوبي الخام وسرعة المعالجة، تتفوق دالة InStr بفارق طفيف وملموس عند فحص النصوص الحرفية المباشرة التي لا تتطلب محارف بديلة؛ والسبب في ذلك يعود إلى أن خوارزميات البحث الداخلي لدالة InStr موجهة للبحث عن تسلسلات بايتات ثابتة في الذاكرة دون الحاجة إلى تشغيل مفسر الأنماط المعقد. فضلاً عن ذلك، توفر دالة InStr خياراً مدمجاً وموضعياً لتحديد نوع المقارنة (نصية أو ثنائية) عبر معاملها الرابع، مما يغني عن استخدام دوال التحويل مثل UCase أو التوجيه Option Compare Text.
في المقابل، ينهار تفوق دالة InStr عندما تبرز الحاجة إلى مطابقة أنماط متغيرة أو دمج أرقام ومحارف مكانية محددة؛ إذ تعجز تماماً عن فحص تعبيرات مثل “محرفان يليهما ثلاثة أرقام”. هنا يظهر التفوق الهندسي المطلق لمعامل Like ونفيه، حيث يمنح المطور منصة تعبيرية شاملة تعوض الفارق الزمني المتواضع، مما يجعل من InStr خياراً للبحث الحرفي البسيط، ومن Not Like خياراً للبحث النمطي التكويني.
9.2 المقارنة بين Not Like والتعبيرات النمطية المنتظمة (VBScript RegEx)
تمثل مكتبة التعبيرات النمطية Microsoft VBScript Regular Expressions 5.5 أقوى أداة لمعالجة النصوص في لغات البرمجة عموماً وفي لغة VBA عبر تقنية الربط الكائني (COM Automation). توفر التعبيرات النمطية (RegEx) ترسانة هائلة من الرموز البرمجية المتقدمة، مثل تكرار المقاطع لعدد عشوائي محدد {n,m}، وفئات المحارف الموسعة، والبحث المتقدم بالاستناد إلى سياق المحارف السابقة أو اللاحقة (Lookahead and Lookbehind).
ومع ذلك، فإن هذه القوة التعبيرية الهائلة تأتي مصحوبة بتكلفة حاسوبية وتنظيمية باهظة؛ فاستدعاء مكتبة RegEx يتطلب إنشاء كائن برمجي في الذاكرة عبر الربط المتأخر CreateObject("VBScript.RegExp") أو الربط المبكر عبر تفعيل مراجع النظام، وهي عملية تستهلك وقتاً طويلاً في التهيئة الأولية وتستهلك موارد إضافية من الذاكرة المؤقتة. علاوة على ذلك، تتميز الشفرات البرمجية التي تعتمد على RegEx بدرجة عالية من التعقيد وصعوبة القراءة لغير المتخصصين مقارنة بتركيب معامل Like البسيط والمقروء.
يبرز الجدول المقارن التالي الفروق الجوهرية بين الأدوات الثلاث للمفاضلة الهندسية بينها:
جدول المفاضلة التقنية بين تقنيات استبعاد الأنماط في VBA:
- Not Like: يدعم المحارف البديلة الأساسية (*, ?, #, [])، لا يتطلب مكتبات خارجية، سرعته الحسابية عالية جداً ومدمجة أصلياً، وتكلفة صيانته منخفضة نظراً لبساطة تركيبه النحوي.
- InStr = 0: يقتصر على النصوص الحرفية المباشرة فقط، لا يتطلب مكتبات خارجية، يتميز بأعلى سرعة معالجة مطلقة في البحث المباشر، وتكلفة صيانته منخفضة للغاية.
- RegExp.Test = False: يدعم كافة الأنماط المتقدمة والتعبيرات المنتظمة المعقدة، يتطلب ربط مكتبة VBScript الخارجية، سرعته أبطأ بسبب عبء تهيئة الكائنات، ويتطلب خبرة متقدمة لصيانته وفهم شفراته.
يتضح من هذا التحليل أن معامل Not Like يمثل التوازن الأمثل لمعظم تطبيقات معالجة الجداول في إكسيل، ما لم تكن هناك متطلبات فحص شديدة التعقيد تفرض اللجوء الحتمي إلى التعبيرات المنتظمة RegEx.
9.3 استراتيجيات تحسين الأداء عند التعامل مع مجموعات البيانات الكبيرة
عندما تمتد جداول البيانات في إكسيل لتشمل مئات الآلاف من الصفوف، فإن قراءة الخلايا وفحصها بالمعامل Not Like خلية تلو الأخرى عبر الكائنات المباشرة Range("A" & i) يؤدي إلى بطء كارثي قد يستغرق دقائق طويلة؛ والسبب أن كل عملية قراءة أو كتابة فردية بين محرك VBA وورقة العمل تتطلب اتصالاً عبر واجهة COM البرمجية، وهو اتصال يستهلك دورات حاسوبية ملحوظة.
لتحقيق أقصى درجات التسريع البرمجي وتخفيض زمن المعالجة إلى أجزاء من الثانية، يتعين استخدام استراتيجية مصفوفات الذاكرة المؤقتة (Memory Arrays). تعتمد هذه التقنية على سحب بيانات النطاق بالكامل وتخزينها في مصفوفة داخل ذاكرة الوصول العشوائي بعملية قراءة وحيدة، ثم تنفيذ حلقة الفحص ومعاملات Not Like كلياً داخل الذاكرة، وأخيراً إعادة كتابة مصفوفة النتائج إلى ورقة العمل بعملية تفريغ مفردة، كما يتضح من النموذج الهندسي المتقدم التالي:
Sub HighPerformanceNotLikeProcessing()
Dim ws As Worksheet
Dim inputData As Variant
Dim outputData As Variant
Dim lastRow As Long
Dim i As Long
Set ws = ThisWorkbook.Sheets(1)
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
If lastRow < 2 Then Exit Sub
' إيقاف تحديث الواجهة لتقليل استهلاك وحدة المعالجة
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' نقل البيانات من ورقة العمل إلى مصفوفة الذاكرة دفعة واحدة
inputData = ws.Range("A2:A" & lastRow).Value2
' حجز مساحة مصفوفة المخرجات بنفس أبعاد مصفوفة المدخلات
ReDim outputData(1 To UBound(inputData, 1), 1 To 1)
' تنفيذ عمليات الفحص والاستبعاد كلياً داخل الذاكرة العشوائية
For i = 1 To UBound(inputData, 1)
If Not (UCase(CStr(inputData(i, 1))) Like "*HOT*") Then
outputData(i, 1) = "Valid Entry"
Else
outputData(i, 1) = "Excluded"
End If
Next i
' كتابة النتائج المعالجة إلى ورقة العمل في عملية كتابة واحدة
ws.Range("B2:B" & lastRow).Value2 = outputData
' استعادة ضبط إعدادات النظام الحيوية
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
يقلص هذا التحول الهندسي الاعتماد على واجهات التطبيق الرسومية ويوفر ما يصل إلى 95% من زمن التشغيل الإجمالي، مما يجعل استخدام معاملات النفي النمطي فائق الفعالية حتى مع أضخم قواعد البيانات المؤسسية.
10. أفضل الممارسات البرمجية والأخطاء الشائعة والحلول الموصى بها
10.1 الأخطاء الشائعة في صياغة الشروط النمطية وكيفية تجنبها
يقود تحليل السجلات البرمجية للمطورين في بيئة VBA إلى رصد مجموعة من الأخطاء المتكررة التي تشوه المنطق التشغيلي لشروط النفي. يبرز في مقدمة هذه الأخطاء نسيان وضع محارف النجمة (*) في بداية النمط أو نهايته عند الرغبة في البحث عن الاحتواء الجزئي. على سبيل المثال، كتابة الشرط If Not (str Like "error") Then لن تستبعد سوى النصوص التي تتطابق حرفياً وتطابقاً تاماً مع كلمة “error” وحدها، وستسمح بمرور نصوص مثل “system error” أو “error 404” دون اعتراض، نظراً لأن غياب النجمة يحول الفحص من بحث جزئي إلى مطابقة كاملة مغلقة.
يتمثل الخطأ الثاني في إغفال الأقواس حول الشروط المركبة، مما يفسح المجال لأسبقية العمليات المنطقية لتقييم الشفرة بطرق غير متوقعة، خاصة عند اقتران النفي بمعاملات الربط مثل And و Or. القاعدة الذهبية هنا هي عدم ترك الأسبقية للتقدير الضمني للمترجم، بل تطويق كل تعبير مقارنة مستقل بأقواس واضحة ومحددة تعكس التسلسل الرياضي الصارم للحل.
كذلك يقع المبرمجون في خطأ محاولة مقارنة الأرقام المخزنة بنوع رقمي صريح (مثل Double أو Long) بنمط نصي يتضمن أرقاماً، مثل Not (cell.Value Like "100*")؛ حيث يؤدي اختلاف الأنواع إلى سلوكيات غير متوقعة وتذبذب في دقة المطابقة. لتفادي ذلك، يتعين دائماً تحويل القيم الرقمية صراحة إلى قيم نصية مكافئة عبر دالة CStr() قبل تقديمها لمعامل Like لضمان تجانس البيانات وسلاسة مطابقتها داخل المحرك البرمجي.
10.2 معايير كتابة كود VBA احترافي وقابل للصيانة والتدقيق
يتطلب الارتقاء بجودة الشفرات البرمجية من مجرد نصوص تشغيلية إلى برمجيات مؤسسية قابلة للصيانة والتطوير الالتزام بمعايير الترميز الصارمة. في هذا السياق، يُوصى باعتماد التدوين المجري (Hungarian Notation) لتسمية المتغيرات والكائنات، من خلال إلحاق بادئة تدل على النوع البياني للمتغير؛ مثل استخدام strText للمتغيرات النصية، وlngRow للأعداد الطويلة، وrngTarget لكائنات النطاقات، مما يسهل قراءة وتدقيق تدفق المتغيرات عبر الأسطر البرمجية المختلفة.
كما يُستحسن عزل منطق فحص الأنماط المعقدة واستبعادها داخل دوال مخصصة مستقلة (UDFs) بدلاً من حشوها داخل الإجراءات الفرعية الرئيسية. يتيح هذا الفصل المعماري للمطور إعادة استخدام قواعد الفحص عبر وحدات نمطية متعددة داخل المشروع، وييسر تعديل الأنماط المستبعدة من مكان مركزي موحد دون الحاجة لتتبعها في مئات الأسطر التشغيلية.
أخيراً، يجب تدعيم الشفرة بالتوثيق الداخلي الرصين عبر التعليقات الشارحة (Comments)، مع توضيح الدلالة التشغيلية لكل محرف بديل تم استخدامه في قوالب النفي، وإخضاع الإجراء لاختبارات الوحدات (Unit Testing) عبر تمرير بيانات حدية (Edge Cases)؛ مثل السلاسل النصية الفارغة، والسلاسل الطويلة جداً، والنصوص التي تحتوي على محارف غير قابلة للطباعة أو رموز خاصة، للتحقق من استقرار المنظومة البرمجية في شتى الظروف التشغيلية.
10.3 مشروع برمجي متكامل: أداة تنقية متقدمة باستخدام Not Like
تتويجاً للمفاهيم الهندسية والتحليلية التي تم تفكيكها في هذا الدليل، يقدم هذا القسم مشروعاً برمجياً متكاملاً لأداة متقدمة لتنقية واستبعاد البيانات غير المطابقة للمواصفات المؤسسية. صُممت هذه الأداة لتقرأ البيانات بكفاءة عبر مصفوفات الذاكرة، مع تفعيل المعالجة الدفاعية ضد الأخطاء الحسابية، وتوحيد حالات الأحرف، وعزل السجلات المشوهة في ورقة عمل مستقلة مخصصة لتقارير التدقيق.
تعتمد الأداة على فحص أكواد الشحنات اللوجستية في العمود A؛ حيث يُشترط لاعتماد الشحنة أن تبدأ بكود الحاوية النظامي المكون من حرفين كبيرين، متبوعين برقمين، ثم خط فاصل، دون أن تحتوي على أي مقطع يشير إلى تلف الشحنة مثل “DMG” أو إلغائها “CAN”. يتم استبعاد وتوثيق أي سجل يخالف هذا النمط المركب بدقة متناهية، كما يتضح من الشفرة البرمجية الكاملة التالية:
Sub AdvancedDataPurgeEngine()
' =========================================================================
' الأداة المؤسسية لتنقية واستبعاد السجلات المعيبة باستخدام Not Like
' =========================================================================
On Error GoTo TechnicalErrorHandler
Dim wsSource As Worksheet
Dim wsAudit As Worksheet
Dim rawData As Variant
Dim validData As Variant
Dim auditData As Variant
Dim totalRows As Long
Dim i As Long
Dim validCounter As Long
Dim auditCounter As Long
Dim currentCode As String
' تهيئة مراجع أوراق العمل
Set wsSource = ThisWorkbook.Sheets("DataSheet")
' إنشاء أو تنظيف ورقة عمل سجلات التدقيق
On Error Resume Next
Set wsAudit = ThisWorkbook.Sheets("AuditReport")
If wsAudit Is Nothing Then
Set wsAudit = ThisWorkbook.Sheets.Add(After:=wsSource)
wsAudit.Name = "AuditReport"
Else
wsAudit.Cells.ClearContents
End If
On Error GoTo TechnicalErrorHandler
' تسريع العمليات البرمجية بتعطيل الواجهة الرسومية
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
' استخراج آخر صف مأهول بالبيانات
totalRows = wsSource.Cells(wsSource.Rows.Count, "A").End(xlUp).Row
If totalRows < 2 Then
MsgBox "لا توجد سجلات كافية للمعالجة في ورقة العمل.", vbExclamation, "تنبيه"
GoTo FinalizeProcess
End If
' سحب البيانات دفعة واحدة إلى مصفوفة الذاكرة المؤقتة
rawData = wsSource.Range("A2:A" & totalRows).Value2
' حجز مساحات المصفوفات التحليلية
ReDim validData(1 To UBound(rawData, 1), 1 To 2)
ReDim auditData(1 To UBound(rawData, 1), 1 To 2)
validCounter = 0
auditCounter = 0
' بدء حلقة الفحص والتدقيق النمطي المتقدم
For i = 1 To UBound(rawData, 1)
' فحص وجود أخطاء معادلات إكسيل في الخلية
If IsError(rawData(i, 1)) Then
auditCounter = auditCounter + 1
auditData(auditCounter, 1) = "Row " & (i + 1)
auditData(auditCounter, 2) = "Excel Formula Error"
ElseIf IsEmpty(rawData(i, 1)) Or Len(Trim(CStr(rawData(i, 1)))) = 0 Then
' استبعاد الخلايا الفارغة
auditCounter = auditCounter + 1
auditData(auditCounter, 1) = "Row " & (i + 1)
auditData(auditCounter, 2) = "Empty or Blank Cell"
Else
currentCode = UCase(Trim(CStr(rawData(i, 1))))
' تطبيق شرط النفي المركب:
' 1. التحقق من الهيكل الأساسي (حرفان ثم رقمان ثم خط فاصل ثم أي محتوى)
' 2. التحقق من عدم احتواء النص على مقاطع الاستبعاد المحظورة (DMG أو CAN)
If (Not currentCode Like "[A-Z][A-Z]##-*") Or _
(currentCode Like "*DMG*") Or _
(currentCode Like "*CAN*") Then
' في حال مخالفة المعايير يتم توثيق السجل في مصفوفة الاستبعاد
auditCounter = auditCounter + 1
auditData(auditCounter, 1) = currentCode
auditData(auditCounter, 2) = "Failed Structural Pattern or Contains Forbidden Substring"
Else
' في حال اجتياز كافة اختبارات النفي يتم اعتماد السجل
validCounter = validCounter + 1
validData(validCounter, 1) = currentCode
validData(validCounter, 2) = "Valid and Conforming"
End If
End If
Next i
' تفريغ النتائج المعتمدة في ورقة البيانات الأصلية
wsSource.Range("B2:C" & totalRows).ClearContents
If validCounter > 0 Then
wsSource.Range("B2").Resize(validCounter, 2).Value2 = validData
End If
' تفريغ تقرير الاستبعاد والتدقيق في ورقة العمل المخصصة
wsAudit.Range("A1:B1").Value2 = Array("Rejected Code", "Exclusion Reason")
If auditCounter > 0 Then
wsAudit.Range("A2").Resize(auditCounter, 2).Value2 = auditData
wsAudit.Columns("A:B").AutoFit
End If
MsgBox "اكتملت عملية التنقية والتدقيق بنجاح!" & vbCrLf & _
"السجلات المقبولة: " & validCounter & vbCrLf & _
"السجلات المستبعدة: " & auditCounter, vbInformation, "تقرير الإنجاز"
FinalizeProcess:
' استعادة المؤشرات التشغيلية للنظام
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Exit Sub
TechnicalErrorHandler:
MsgBox "حدث خطأ تقني غير متوقع أثناء المعالجة: " & Err.Description, vbCritical, "خطأ نظام"
Resume FinalizeProcess
End Sub
يقدم هذا الإجراء البرمجي نموذجاً متكاملاً لما ينبغي أن تكون عليه الحلول البرمجية في المؤسسات؛ حيث يجمع بين حماية النظام ضد الأخطاء، وكفاءة الذاكرة عبر المصفوفات، وقوة التعبير النمطي المنفي عبر معاملات Like و Not، مع توفير توثيق تدقيقي كامل للسجلات التي تم استبعادها، مما يضمن أقصى درجات الشفافية وسلامة البيانات في بيئات العمل الحساسة.
خاتمة
في الختام، يتضح أن استيعاب الآلية البرمجية لتنفيذ مفهوم “NOT LIKE” في لغة Visual Basic for Applications يمثل خطوة أساسية لكل مبرمج يسعى لبناء حلول أتمتة متقدمة وتطوير خوارزميات رصينة لتنقية البيانات في مايكروسوفت إكسيل. إن غياب معامل ثنائي مدمج يحمل هذا الاسم لم يكن عائقاً أمام تطويع اللغة، بل شكّل مدخلاً لتطبيق قواعد المنطق البولياني عبر دمج المعامل المنطقي الأحادي Not مع معامل المقارنة النمطية Like، مما أتاح إمكانية تفكيك السلاسل النصية واستبعاد الأنماط غير المتوافقة بدقة بالغة.
تُظهر الممارسات الهندسية أن النجاح في توظيف هذه التقنية لا يقتصر على كتابة الشفرة النحوية الصحيحة فحسب، بل يتطلب إدراكاً عميقاً لبيئة التشغيل بكافة أبعادها؛ بدءاً من فهم قواعد أسبقية العمليات، ومراعاة الفروق الحاسوبية بين المقارنة الثنائية والمقارنة النصية غير الحساسة للأحرف عبر Option Compare، ومروراً بالتعامل الدفاعي مع أخطاء المعادلات والقيم المنعدمة، وصولاً إلى تحسين الأداء الحسابي عبر توظيف مصفوفات الذاكرة لتقليل الاحتكاك بواجهة التطبيق في البيانات الضخمة. إن اتباع هذه المعايير يضمن بقاء التطبيقات البرمجية آمنة ومستقرة، وقادرة على خدمة قطاعات الأعمال بكفاءة وموثوقية عالية.
المراجع
- Microsoft Corporation. (2023). Like operator (Visual Basic for Applications). Microsoft Learn. https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/like-operator
- Microsoft Corporation. (2023). Not operator (Visual Basic for Applications). Microsoft Learn. https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/not-operator
- Microsoft Corporation. (2023). Option Compare statement (Visual Basic for Applications). Microsoft Learn. https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/option-compare-statement
- Microsoft Corporation. (2023). Operator precedence summary (Visual Basic for Applications). Microsoft Learn. https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/operator-precedence-summary
- Walkenbach, J. (2015). Excel 2016 Power Programming with VBA. John Wiley & Sons.