المحتوى عن 'دوال'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • نصائح وإرشادات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • التجارة الإلكترونية
  • مقالات عامة

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML5
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات عامّة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • مقالات عامّة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 18 نتائج

  1. في هذا الدرس سنستعرض بعض دوال النصوص المضمّنة في مكتبة دوال اكسل ونوضّح من خلال الأمثلة كيفية استخدامها لتطبيق إجراءات مختلفة على القيم النصيّة مثل، البحث عن النصوص واستبدالها، تنسيق حالة الأحرف للنصوص الإنجليزية، وغيرها. TRIM تعمل هذه الدالة على إزالة المسافات الزائدة بين الكلمات، أو في بداية ونهاية السلسلة النصية. والصيغة العامة لها هي: =TRIM(text) text: النص الذي نريد إزالة المسافات الزائدة منه. مثال: تحتوي الخلية B4 الموضّحة أدناه على مسافات غير منتظمة بين الكلمات، ولحذف المسافات غير المرغوبة نكتب الصيغة التالية في خلية النتيجة: بإمكاننا تحديد الخلية التي تحتوي على النص مباشرة، أو لصق النص يدويًا بين علامتي اقتباس (" "). نضغط على ENTER لإظهار النتيجة: كما نلاحظ في خلية النتيجة، تمت إزالة كل المسافات الزائدة باستثناء المسافات الفردية بين الكلمات. يمكننا استخدام هذه الدالة عند استيراد النصوص إلى اكسل ويكون تباعد الكلمات فيها غير منتظم. إذ ستكون عملية إزالة المسافات الزائدة أسهل وأسرع بكثير من القيام بها يدويًا. PROPER تعمل هذه الدالة على تحويل الحرف الأول من كل كلمة في السلسة النصية إلى حرف كبير وتبقي بقية الحروف صغيرة. ويمكننا الاستفادة منها عند استيراد نصوص معيّنة إلى اكسل وكانت حالة الأحرف للكلمات غير مرتّبة، إذ ستجعل هذه الدالة عملية تنسيق حالة الأحرف أسرع وأسهل بكثير من القيام بها يدويًا. الصيغة العامة لهذه الدالة: =PROPER(text) text: النص الذي نريد تطبيق الدالة عليه. مثال: تحتوي الخلية B5 الموضحة أدناه على نص باللغة الإنجليزية، وحالة الأحرف للكلمات غير منتظمة، لتعديل النص وجعل كل كلمة تبدأ بحرف كبير وبقية الحروف صغيرة، نكتب الصيغة التالية في خلية النتيجة: يمكننا تحديد الخلية التي تحتوي على النص، أو لصق النص غير المرتب بين علامتي اقتباس في الصيغة. نضغط على مفتاح ENTER لإظهار النتيجة: من خصائص دالة PROPER هو أنّه حتّى إذا كانت بداية الكلمة أرقام أو رموز (مثل 09test)، فأنّها تتجاوز الأرقام وتحوّل الحرف الأول إلى حرف كبير (أي تصبح الكلمة المذكورة 09Test). FIND تُستخدم هذه الدالة لتحديد موقع كلمة/عبارة معيّنة ضمن سلسلة نصيّة. فتقوم بإرجاع ترتيب الحرف الأول للكلمة التي نبحث عنها نسبة إلى عدد حروف السلسلة. وتكون هذه الدالة حساسة لتشكيل الكلمة في اللغة العربية ولحالة الأحرف (كبيرة أو صغيرة) في اللغة الإنجليزية. الصيغة العامة للدالة: =FIND(find_text; within_text; [start_num]) find_text: النص الذي نبحث عنه، وهو مطلوب في الصيغة. within_text: النص الذي نريد البحث فيه، وهو أيضًا مطلوب في الصيغة. start_num: مرتبة الحرف الذي نريد بدء البحث منه، ووجوده اختياري في الصيغة (معطيات الصيغة التي توضع بين قوسين مربعين [ ] تكون اختيارية). مثال: لمعرفة موقع كلمة "Functions" في نص الخلية G3 نكتب الصيغة التالية: نراعي وضع الكلمة التي نريد البحث عنها بين علامتي اقتباس في الصيغة ونتأكّد من مطابقة حالة الأحرف، ثم نضغط على مفتاح ENTER لإظهار النتيجة: تم إرجاع النتيجة "6" وهو بالفعل تسلسل أول حرف في كلمة "Functions". فكلمة "Text" تحتل 4 مراتب، والمسافة بين "Functions" و"Text" تأخذ مرتبة واحد ليصبح المجموع 5، وحرف "F" هو السادس. في هذا المثال لم نحدد قيمة start_num، وفي هذه الحالة سيتم افتراض هذه القيمة 1، أي يبدأ البحث من أول حرف في النص. لنغيّر الصيغة ونحدد قيمة المتغيّر start_num 17 مثلا: بالنتيجة تم إرجاع الخطأ #VALUE! لأنّه لم يتم العثور على كلمة "Functions" بعد المرتبة 17. فكلمتي "Text" و"Functions" مع المسافة بينهما تحتل 14 مرتبة، بمعنى أنّ كلمة "Functions" تقع قبل المرتبة 17: لنغيّر الصيغة ونبحث عن موقع كلمة "حسوب" في الخلية G2، وكالتالي: عند الضغط على مفتاح ENTER تم إرجاع الخطأ #VALUE! وذلك لأننا قمنا بإضافة ضمّة فوق حرف السين عند كتابة الصيغة، وكما أسلفنا الذكر، تكون دالة FIND حسّاسة لتشكيل الحروف في اللغة العربية. SEARCH تماثل دالة FIND من حيث الوظيفة، لكنّها غير حسّاسة لتشكل الحروف في اللغة العربية وحالتها في اللغة الإنجليزية. الصيغة العامة للدالة: =FIND(find_text; within_text; [start_num]) find_text: النص الذي نبحث عنه، وهو مطلوب في الصيغة. within_text: النص الذي نريد البحث فيه، وهو أيضًا مطلوب في الصيغة. start_num: ترتيب الحرف الذي نريد بدء البحث منه، ووجوده اختياري في الصيغة. مثال: سنطبّق هذه الدالة لتحديد موقع الكلمة "Functions" كما في المثال السابق: سنلاحظ أنّه سيتم إرجاع نفس النتيجة، "6"، بالرغم من أننا كتبنا بداية كلمة "functions" بحرف صغير: REPLACE تستخدم هذه الدالة لاستبدال نص معيّن في سلسلة نصيّة بنص آخر حسب عدد الحروف الذي نحدّده. ووظيفتها مشابهة لوظيفة أداة استبدال النصوص Replace. الصيغة العامة للدالة: =REPLACE( old_text; start_num; num_chars; new_text ) old_text: السلسلة النصية التي نريد استبدال جزء منها. start_num: مرتبة الحرف الأول للنص الذي نريد استبداله. num_chars: عدد حروف النص القديم الذي نريد استبداله. new_text: النص الجديد الذي نريد الاستبدال به. ملاحظة: كل المتغيرات أعلاه مطلوبة في الصيغة. مثال: لاستبدال كلمة "النصوص" في الخلية G2 بالكلمة "نصية"، نكتب الصيغة كالتالي: قمنا بإدخال الخلية G2 في الصيغة لأنّها تحتوي على النص الأصلي الذي نريد استبدال جزء منه، يليه الرقم "6" لأنّ مرتبة أول حرف من كلمة "النصوص هي السادسة (كلمة "دوال" مع المسافة بعدها تحتل 5 مراتب، وكلمة "النصوص" تبدأ عند المرتبة 6)، يليه الرقم "6" لأنّ كلمة "النصوص" تتكوّن من ستّة حروف، وأخيرًا كلمة "نصيّة" التي نريد الاستبدال بها بين علامتي اقتباس. والنتيجة: UPPER تقوم هذه الدالة بجعل كل أحرف السلسلة النصيّة كبيرة. والصيغة العامة لها هي: =UPPER(text) text: النص الذي نريد تطبيق الدالة عليه. مثال: لتحويل كل النصوص في الخلية B5 إلى أحرف كبيرة نكتب الصيغة التالية: والنتيجة: LOWER عملها معاكس للدالة السابقة، إذ تجعل كل أحرف السلسلة النصية صغيرة. الصيغة العامة لهذه الدالة هي: =LOWER(text) مثال: لتحويل نفس النص في الخلية B5 إلى أحرف صغيرة نكتب الصيغة التالية: والنتيجة: خاتمة لقد تعلّمنا كيفية إزالة المسافات الزائدة بين النصوص، كيفية البحث عن نصوص معيّنة واستبدالها، وكيفية تغيير حالة الأحرف باستخدام بعض الدوال النصيّة. في الدرس القادم سنغطّي المزيد من هذه الدوال ونتعلّم كيفية تجميع النص وكيفية استخلاص جزء منه.
  2. لقد تعرّفنا في درس سابق على بعض دوال اكسل النصيّة، مثل دالة TRIM لإزالة المسافات الزائدة بين النصوص، الدوال FIND، SEARCH، وREPLACE للبحث عن النصوص واستبدالها، ودالتي UPPER وLOWER لتغيير حالة الأحرف للنصوص الإنجليزية. في هذا الدرس سنتعلّم كيف نطبّق المزيد من الإجراءات على النصوص في اكسل باستخدام الدوال، ونوضّح ذلك من خلال الأمثلة التطبيقية. LEFT تُستخدم دالة LEFT لاستخراج جزء من النص من جهة اليسار للسلسلة النصية حسب عدد الأحرف الذي نحدده. والصيغة العامة لهذه الدالة هي: =LEFT(text; [num_chars]) text: النص الذي نريد استخراج جزء منه. num_chars: عدد الأحرف التي نريد استخراجها. وبما أنّ وجوده اختياري في الصيغة، سيتم افتراض العدد 1 عند عدم تحديد هذه القيمة. مثال: إذا رغبنا في استخراج كلمة "Text" من نص الخلية B4 نستخدم الدالة LEFT (لأنّ الكلمة تقع في جهة اليسار من السلسلة النصية) ونكتب الصيغة التالية: قمنا بتحديد الخلية B4 لأنها تحتوي على النص الذي نريد الاستخراج منه، وقمنا بكتابة الرقم 4 لأنّ كلمة "Text" تتكوّن من أربعة حروف. نضغط على مفتاح ENTER لإظهار النتيجة: إذا لم نحدد قيمة num_chars في الصيغة سيتم افتراض القيمة 1 وإرجاع النتيجة "T" لأنّ هذا الحرف يحتل المرتبة الأولى من جهة اليسار: إذا استخدمنا هذه الدالة مع نص مكتوب باللغة العربية، سينعكس اتجاه عمل الدالة وتقوم باستخراج جزء من النص من جهة اليمين للسلسلة النصية. أي بشكل أدق يمكننا القول أنّ الدالة تستخرج النص الذي يقع في موضع معيّن من بداية السلسلة النصية. على سبيل المثال، إذا قمنا بتطبيق نفس الصيغة أعلاه على الخلية B5: سيتم استخراج كلمة "دوال" من الخلية، والتي هي في الحقيقة تقع على يمين، وليس يسار، السلسلة النصية: RIGHT عمل هذه الدالة معاكس لعمل الدالة السابقة. إذ تقوم باستخراج جزء من النص الذي يقع على يمين السلسلة النصية حسب عدد الأحرف الذي نحدده. والصيغة العامة لها هي: =RIGHT(text; [num_chars]) text: النص الذي نريد استخراج جزء منه. num_chars: عدد الأحرف التي نريد استخراجها. وبما أنّ وجوده اختياري في الصيغة، سيتم افتراض العدد 1 عند عدم تحديد هذه القيمة. مثال: إذا رغبنا في استخراج كلمة "Academy" من النص في الخلية B4 نستخدم الدالة RIGHT (لأنّ الكلمة تقع على يمين السلسلة النصية) ونكتب الصيغة التالية: قمنا بإدخال الرقم 7 لأنّ كلمة "Academy" تتكوّن من 7 حروف. نضغط على مفتاح ENTER لإظهار النتيجة: MID تُستخدم دالة MID لاستخراج جزء من النص يقع في مرتبة محددة من بداية السلسلة النصية وحسب عدد الأحرف الذي نحدّده. الصيغة العامة لهذه الدالة: =MID(text; start_num; num_chars) text: النص الذي نريد الاستخراج منه. start_num: موضع/مرتبة الحرف الأول للنص الذي نريد استخراجه. num_chars: عدد أحرف النص الذي نريد استخراجه. مثال: إذا رغبنا في استخراج كلمة "Hsoub" من النص في الخلية B4 باستخدام الدالة MID، نكتب الصيغة التالية: قمنا بإدخال الرقم 18 لأنّ الحرف الأول من كلمة "Hsoub" يقع في المرتبة 18، والرقم خمسة لأنّ عدد حروف كلمة "Hsoub" يساوي 5. نضغط على ENTER لإظهار النتيجة: CONCATENATE تُستخدم دالة CONCATENATE لجميع جزأين أو أكثر من النصوص في سلسلة نصيّة واحدة. والصيغة العامة لهذه الدالة هي: =CONCATENATE(text1; [text2];…) text1: النص الأول الذي نريد دمجه. text2: النص الثاني الذي نريد دمجه مع النص الأول. يمكن أن تكون العناصر التي نريد تجميعها قيم نصّية، رقمية، أو مرجع خلية. مثال: إذا رغبنا في تجميع النص من خلايا متفرّقة، ولتكن G3 وD7، بالإضافة إلى الرقم "2"، نكتب الصيغة التالية: قمنا بإدخال مسافة فارغة بين علامتي اقتباس (" ") بعد G3 وD7 لأننا نريد أن نفصل النصوص بمسافة، وإلّا ستظهر الكلمات متلاصقة. نضغط على ENTER لإظهار النتيجة: لقد نجحنا في المثال بتجميع النصوص من خلايا متفرّقة، أحد هذه النصوص هو نتيجة لصيغة قمنا بتطبيقها سابقًا (كلمة "Text")، والنص الثاني هو عبارة عن قيمة نصيّة (Functions)، أما الأخير فهو قيمة رقمية ("2") قمنا بإدخالها يدويًا في الصيغة. بإمكاننا أيضًا استخدام علامة العطف (&) لتجميع النصوص بدلًا من الدالة CONCATENATE. على سبيل المثال، إذا رغبنا في جمع النصوص في G4 وG5 باستخدام العلامة & نكتب الصيغة التالية: علامة & هي في الحقيقة ليست دالة، واستخدامها مشابه تقريبًا لاستخدام علامة الجمع (+) مع القيم الرقمية. نراعي عند جمع النصوص هنا أيضًا وضع مسافة فارغة بين علامتي اقتباس بين النصوص لتلافي تلاصقها. نضغط على ENTER لإظهار النتيجة: EXACT تُستخدم هذه الدالة للمقارنة بين النصوص والتأكّد فيما إذا كانت متطابقة. فتقوم بإرجاع القيمة المنطقية TRUE إذا كانت متطابقة، والقيمة المنطقية FALSE إن لم تكن كذلك. وتكون دالة EXACT حساسة لتشكيل الأحرف في اللغة العربية وحالتها (صغيرة أو كبيرة) في اللغة الإنجليزية لكنّها لا تقارن تنسيق النص. الصيغة العامة للدالة: =EXACT(text1; text2) text1: النص الأول الذي نريد مقارنته. text2: النص الثاني الذي نريد مقارنته. مثال: لمقارنة النصين في الخليتين B3 وC7 نكتب الصيغة التالية: تم إرجاع النتيجة FALSE لعدم وجود همزة فوق حرف الألف لكلمة "اكاديمية" في الخلية C7، وهذه الدالة كما ذكرنا حسّاسة لتشكيل الأحرف: تسهّل هذه الدالة أيضًا مقارنة الأرقام، فإذا كانت الأرقام طويلة وفي مواضع متفرّقة من الورقة سيكون من الأدق مقارنتها باستخدام دالة EXACT. سنقوم مثلا بمقارنة الرقمين في الخليتين B2 وC6 بكتابة الصيغة التالية: وسنتأكّد من تطابق الرقمين عند إرجاع النتيجة TRUE: LEN تقوم هذه الدالة بحساب طول السلسلة النصية فتقوم بإرجاع عدد أحرف النص. والصيغة العامة لها هي: =LEN(text) text: النص الذي نريد تطبيق الدالة عليه. مثال: لحساب عدد أحرف النص في الخلية G6 نكتب الصيغة التالية: سيتم تضمين المسافات بين الكلمات عند إرجاع النتيجة: بإمكاننا أن نضيف إلى نتيجة هذه الدالة كلمة توضيحية باستخدام العلامة &. على سبيل المثال، لإضافة كلمة "حرف" بعد عدد الأحرف الذي ترجعه الدالة، نكتب الصيغة كالتالي: والنتيجة: كما بإمكاننا استخدامها مع الدوال الأخرى سالفة الذكر. على سبيل المثال نستطيع استخدامها لحساب عدد أحرف سلسلتين نصيتين مدموجتين باستخدام دالة CONCATENATE. وتكون الصيغة في هذه الحالة كالتالي: والنتيجة: خاتمة لقد استعرضنا بعض الدوال النصيّة التي يمكن أن تكون مفيدة لتسهيل بعض المهام وتوفير الوقت عند العمل على اكسل. فيمكننا مثلا استخدام دوال الاستخراج لنسخ إجزاء من النصوص في موقع معيّن من الخلية دون الحاجة إلى نسخة يدويًا. كما يمكننا استخدام دالة الدمج مع أمر التعبئة التلقائية لدمج بيانات عمودين في عمود واحد بشكل سريع، وغيرها من الاستخدامات الفوائد حسب ما يلائم حاجة المستخدم. إن كان لديكم أي سؤال بخصوص دوال النصوص تفضّلوا بطرحه في صندوق التعليقات.
  3. لقد استعرضنا في الدرس السابق قائمة دوال Date و Time، وهي دوال التاريخ الأساسية، وتعلّمنا كيفية استخدامها للحصول على بيانات معيّنة تتعلّق بالتاريخ. وفي هذا الدرس سنتعرّف على دوال الوقت الأساسية ونوضّح كيفية استخدامها بواسطة الأمثلة التوضيحية. NOW تقوم هذه الدالة بإرجاع الوقت والتاريخ الحالي، والصيغة العامة لها: =NOW() مثال: لعرض تاريخ اليوم والوقت الحالي في الخلية G2 نكتب الصيغة التالية: بما أنّ عمل الدالة لا يتطلّب تحديد أي متغيّر، نترك ما بين القوسين فارغًا ثم نضغط على مفتاح ENTER لعرض النتيجة: HOUR تعمل هذه الدالة على استخراج جزء الساعة من الوقت، والصيغة العامة لها هي: =HOUR(serial_number) serial_number: الوقت الذي نريد استخراج جزء الساعة منه. ويمكن إدخال هذا الوقت يدويًا كسلسلة نصيّة بين علامتي اقتباس، أو تحديد خلية تحتوي على صيغة تكون نتيجتها وقتًا معيّنًا. مثال: لاستخراج جزء الساعة من ناتج الصيغة في الخلية G2، نكتب الصيغة التالية: وبالنتيجة سيتم إرجاع الرقم "20" الذي يمثّل جزء الساعة من الوقت: ويمكن أيضًا أن تكون الصيغة بالشكل التالي: في هذه الحالة سيتم إرجاع الرقم "9" الذي يمثّل جزء الساعة: MINUTE ترجع هذه الدالة جزء الدقائق من الوقت الذي نحدّده في الصيغة، والصيغة العامة لها هي: =MINUTE(serial_number) serial_number: الوقت الذي نريد استخراج جزء الدقائق منه. ويمكن إدخال هذا الوقت يدويًا كسلسلة نصيّة بين علامتي اقتباس، أو تحديد خلية تحتوي على صيغة تكون نتيجتها وقتًا معينًا. مثال: لاستخراج جزء الدقائق من الوقت في الخلية G2، نكتب الصيغة التالية: وبالنتيجة سيتم إرجاع الرقم "31" الذي يمثل جزء الدقائق: ملاحظة: سيتم تحديث ناتج صيغة الدالة NOW كلّما قمنا بكتابة وتطبيق صيغة ما في الورقة، سواء كانت مرتبطة بصيغة الدالة NOW أو غير مرتبطة بها. كما سيتم تحديثه كلّما قمنا بإغلاق المصنّف وفتحه مجددًا. SECOND تستخرج هذه الدالة جزء الثواني من الوقت الذي نحدّده في الصيغة، والصيغة العامة لها هي: =SECOND(serial_number) serial_number: الوقت الذي نريد استخراج جزء الدقائق منه. ويمكن إدخال هذا الوقت يدويًا كسلسلة نصيّة بين علامتي اقتباس، أو تحديد خلية تحتوي على صيغة تكون نتيجتها وقتًا معيّنًا. مثال: لاستخراج جزء الثواني من الوقت في الخلية G2، نكتب الصيغة التالية: والنتيجة: بما أننا قمنا بتطبيق الصيغة على ناتج الدالة NOW، سيتم إرجاع جزء الثواني في وقت تطبيق الصيغة. وسيتغيّر هذا الرقم كلّما قمنا بتحديث الصيغة. أمّا إذا قمنا بإدخال الوقت يدويًا كنص بين علامتي اقتباس، فسيبقى ناتج الدالة ثابتًا مهما قمنا بتحديث الصيغة. TIME تقوم هذه الدالة بإرجاع الوقت اعتمادًا على رقم الساعة، الدقيقة، والثانية الذي نقوم بتحديده. والصيغة العامة لها هي: =TIME(hour; minute; second) hour: الرقم الذي يمثّل الساعة. وأي رقم أكبر من 23 سيتم تقسيمه على 24، ويعتبر الباقي جزء الساعة من الوقت. minute: الرقم الذي يمثّل الدقائق. وأي رقم أكبر من 59 سيتم تقسمه على 60، ويتم تحويل الباقي إلى ساعات ودقائق. second: الرقم الذي يمثّل الثواني. وأي رقم أكبر من 59 سيتم تقسيمه على 60، ويتم تحويل الباقي إلى ساعات ودقائق وثواني. مثال: لتحويل الساعة 08، الدقيقة 20، الثانية 50 إلى تنسيق وقت نكتب الصيغة التالية: والنتيجة: يمكننا تغيير تنسيق الوقت لإظهار الثواني أو استخدام تنسيقات أخرى من مربّع الحوار Format Cells. مثال آخر؛ لتحويل الساعة 26، الدقيقة 05، الثانية 63 إلى تنسيق وقت، نكتب الصيغة التالية: والنتيجة: لقد عملت الدالة كالتالي: بما أنّ رقم الساعة أكبر من 24، تم تقسيم الرقم 26 على 24 واعتبار باقي عملية القسمة العدد 2 هو الجزء الذي يمثل الساعة. وهذا منطقي، فالساعة 26 يعني ساعتين بعد الساعة 24، أي الساعة الثانية صباحًا. وبما أنّ رقم الثواني أكبر من 60، تم تقسيم الرقم 63 على الرقم 60، ومن ثم إضافة ناتج القسمة الصحيح، العدد 1، إلى الدقائق لتصبح 6 دقائق، وأخيرًا تم اعتبار المتبقي من عملية القسمة الرقم 3 هو الجزء الذي يمثّل الثواني. TIMEVALUE تقوم هذه الدالة بتحويل الوقت المدخل بشكل نص إلى رقم تسلسلي يمثّل هذا الوقت حسب ما تم تخزينه في اكسل. ولكي يتوضّح عمل الدالة، من الأفضل أن نوضّح كيف يُخزن الوقت في اكسل. كل قيمة للوقت تُخزن في اكسل كأرقام تتراوح بين 0 و1، والتي تمثّل بدورها نسبة من اليوم. على سبيل المثال، يمثل الرقم 0.25 الوقت 06:00، أما الرقم 0.5، فيمثّل الوقت 12:00... وهكذا. الصيغة العامة لدالة TIMEVALUE هي: =TIMEVALUE(time_text) time_text: النص الذي يمثل الوقت. مثال: لمعرفة الرقم التسلسلي للوقت "18:40:55"، نكتب الصيغة التالية: نراعي وضع الوقت بين علامتي اقتباس ثم نضغط على ENTER لعرض النتيجة: خاتمة لقد غطيّنا في هذا الدرس دوال الوقت الأساسية في اكسل التي يمكن الاستفادة منها في استخراج بيانات معيّنة متعلّقة بالوقت. وبالطبع المجال مفتوح أمامك كمستخدم لاستخدامها بالطريقة التي تلائم احتياجاتك. إن كان لديك أي سؤال حول دوال الوقت أو ملاحظة ترغب في مشاركتها، تفضّل بطرحها في صندوق التعليقات.
  4. تتألف جداول اكسل التي نقوم بإنشائها من أنواع مختلفة من البيانات، وتعتبر بيانات الوقت والتاريخ جزءًا هامًا منها. ولاستخلاص معلومات معيّنة متعلّقة بالتاريخ يوفّر اكسل مجموعة دوال تندرج تحت قائمة Date & Time في مكتبة الدوال. سنتعرّف في هذا الدرس على بعض دوال التاريخ الأساسية ونوضّح وظيفتها وطريقة استخدمها من خلال الأمثلة التطبيقية. TODAY تقوم هذه الدالة بإرجاع تاريخ اليوم الحالي، والصيغة العامة لها هي: =TODAY() مثال: لمعرفة تاريخ اليوم بواسطة دالة TODAY نكتب الصيغة التالية: عمل الدالة لا يتطلّب تحديد متغيّرات، لذا نبقي الأقواس فارغة ونضغط على ENTER للحصول على النتيجة: MONTH تقوم هذه الدالة باستخراج رقم الشهر لتاريخ نحدّده في الصيغة. والصيغة العامة لها هي: =MONTH(serial_number) serial_number: التاريخ الذي نريد استخراج رقم الشهر منه. ويمكن أن يكون هذا المتغير خلية تحتوي على تاريخ معيّن، أو خلية تحتوي على صيغة تكون نتيجتها تاريخًا معيّنًا. مثال: لاستخراج رقم الشهر للتاريخ في الخلية G2، والذي هو عبارة عن ناتج صيغة أخرى، نكتب الصيغة التالية: سيتم إرجاع رقم الشهر للتاريخ المحدّد: بإمكاننا أيضًا أن نكتب الصيغة بالطريقة التالية وسنحصل على نفس النتيجة: يمكننا استخدام هذه الدالة إذا كان لدينا جدول بيانات كبير ونريد العثور على البيانات المرتبطة بشهر معيّن. في هذه الحالة يمكننا استخراج رقم الشهر لكل التواريخ في عمود منفصل، ومن ثم الوصول بسرعة إلى البيانات الخاصة بالشهر المطلوب دون الحاجة إلى التحقق من كل تاريخ على حدة. DAY عملها مشابه لعمل الدالة السابقة، إذ تقوم باستخراج رقم اليوم لتاريخ يحدّده المستخدم في الصيغة. والصيغة العامة لهذه الدالة هي: =DAY(serial_number) serial_number: التاريخ الذي نريد استخراج رقم اليوم منه. ويمكن أن يكون هذا المتغير خلية تحتوي على تاريخ معيّن، أو خلية تحتوي على صيغة تكون نتيجتها تاريخًا معيّنًا. مثال: لاستخراج رقم اليوم للتاريخ في الخلية G2، نكتب الصيغة التالية: وبالنتيجة سنحصل على الرقم "26" والذي هو رقم اليوم للتاريخ المحدّد: YEAR عمل هذه الدالة أيضًا مشابه لعمل الدالتين السابقتين، إذ تقوم بإرجاع رقم السنة للتاريخ الذي نحدّده في الصيغة. والصيغة العامة لها هي: =YEAR(serial_number) serial_number: التاريخ الذي نريد استخراج رقم السنة منه. ويمكن أن يكون هذا المتغير خلية تحتوي على تاريخ معيّن، أو خلية تحتوي على صيغة تكون نتيجتها تاريخًا معيّنًا. مثال: لاستخراج رقم السنة من التاريخ في الخلية G2 نكتب الصيغة التالية: وبالنتيجة سيتم إرجاع الرقم "2016": DATE تقوم هذه الدالة بتحويل أرقام السنة، الشهر، واليوم التي نحدّدها إلى تنسيق تاريخ. والصيغة العامة لها هي: =DATE(year; month; day) year; month; day: أرقام صحيحة تمثل السنة، الشهر، واليوم على التوالي. ويمكن أن نقوم بإدخالها يدويًا في الصيغة، أو تحديدها من خلية تحتوي على رقم مدخل يدويًا أو رقم ناتج من صيغة. مثال: لتحويل الأرقام في الخلايا G3، G4، وG5 إلى تنسيق تاريخ، نكتب الصيغة التالية: نضغط على ENTER لإظهار نتيجة الصيغة: طريقة أخرى لكتابة الصيغة: والنتيجة التي سيتم إرجاعها هي: DATEVALUE تقوم هذه الدالة بتحويل التاريخ المدخل بشكل نص إلى رقم تسلسلي يمثل هذا التاريخ حسب ما هو مخزّن في اكسل. وتجدر الإشارة هنا إلى أنّ التواريخ في اكسل تخزن بهيئة أرقام تسلسلية صحيحة وموجبة تبدأ من الرقم 1. وبالتالي فإنّ كل تاريخ يقابله رقم معيّن في اكسل. على سبيل المثال: الرقم 1 = 01 كانون الثاني، 1900 الرقم 2= 02 كانون الثاني، 1900 الرقم 32= 01 شباط، 1900 وهكذا... أي بعبارة أخرى يمكننا القول أنّ اكسل يخزن التاريخ كعدد الأيام منذ 01 كانون الثاني (يناير)، 1900. الصيغة العامة لهذه الدالة هي: =DATEVALUE(date_text) date_text: النص الذي يمثل التاريخ. مثال: لمعرفة الرقم التسلسلي للتاريخ "26/11/2016" نكتب الصيغة التالية: وكما موضّح في الصيغة أعلاه، قمنا بإدخال التاريخ بشكل نص بين علامتي اقتباس وليس كمرجع خلية كما فعلنا مع بقية الدوال. نضغط ENTER لإرجاع النتيجة: نلاحظ أنّ تنسيق الرقم في خلية النتيجة هو عام General، وعندما نغيّر التنسيق إلى تاريخ، سيتحوّل هذا الرقم التسلسلي إلى نفس التاريخ الذي قمنا بإدخاله في الصيغة: WEEKDAY تقوم هذه الدالة بإرجاع رقم صحيح يمثّل تسلسل اليوم في الأسبوع حسب التاريخ المحدّد في الصيغة. والصيغة العامة لها هي: =WEEKDAY(serial_number; [return_type]) serial_number: تاريخ اليوم الذي نريد تطبيق الدالة عليه. return_type: قيمة اختيارية تحدّد أي رقم يخصّص لكل يوم من أيام الأسبوع. الجدول التالي يوضّح قيم return_type والأرقام المقابلة المخصصة لكل يوم في الأسبوع. إذا لم نقم بتحديد قيمة return_type سيتم افتراضها مساوية لرقم 1. مثال: لمعرفة رقم اليوم "26/11/2016" في الأسبوع، نكتب الصيغة التالية: بالنتيجة تم إرجاع الرقم 7. أي أنّ اليوم، السبت، هو سابع يوم في الأسبوع على افتراض أنّ قيمة return_type= 1 لأننا لم ندخلها في الصيغة. وحسب الجدول الموضّح أعلاه، يمثل الرقم 7 يوم السبت من الأسبوع: أمّا إذا قمنا بتحديد قيمة return_type في الصيغة، ولتكن 16 مثلا: سيتم إرجاع الرقم 1، على فرض أنّ السبت هو أول أيام الأسبوع حسب الجدول أعلاه: WEEKNUM تقوم هذه الدالة بإرجاع رقم صحيح يمثّل تسلسل الأسبوع في السنة حسب التاريخ المحدّد في الصيغة. والصيغة العامة لها هي: =WEEKDAY(serial_number; [return_type]) serial_number: التاريخ الذي نريد تطبيق الدالة عليه. return_type: قيمة اختيارية تحدّد أي نظام ترقيم نريد استخدامه وأي يوم في الأسبوع نريد اعتباره اليوم الأول في الأسبوع. يوجد نظامان لترقيم الأسابيع في السنة: النظام 1: وفيه يتم اعتبار الأسبوع الذي يتضمّن تاريخ 1 كانون الثاني هو الأسبوع الأول في السنة. النظام 2: وفيه يتم اعتبار الأسبوع الذي يتضمّن أول يوم خميس في السنة هو الأسبوع الأول في السنة. الجدول أدناه يوضّح قيم return_type وبدايات الأسبوع التي تقابلها حسب النظام المستخدم: إذا لم نقم بتحديد قيمة return_type سيتم افتراضها مساوية لرقم 1. مثال: لمعرفة رقم الأسبوع الحالي في عام 2016 حسب التاريخ 26/11/2016 (المدخل في الخلية G2) نكتب الصيغة التالية: سيتم إرجاع الرقم 48، أي أنّ الأسبوع الحالي هو الأسبوع رقم 48 في السنة على اعتبار أن الأسبوع الذي يتضمّن تاريخ 1 كانون الثاني هو الأسبوع الأول في السنة وأنّ الأسبوع يبدأ من يوم الأحد (علمًا أن التاريخ 26/11/2016 يصادف يوم السبت) أما إذا حددنا الرقم 16 كقيمة return_type كما في الصيغة أدناه: سنلاحظ أنّ تسلسل نفس الأسبوع أصبح 49، وذلك لأنّه عند القيمة 16 يتم اعتبار يوم السبت هو بداية الأسبوع، والتاريخ الذي قمنا بتحديد في الصيغة يصادف يوم السبت، أي بداية أسبوع جديد: خاتمة لقد تعرّفنا في هذا الدرس على دوال التاريخ الأساسية وعلى كيفية استخدامها لمعرفة تاريخ اليوم واستخراج رقم اليوم، الشهر، والسنة من التاريخ. كما استخدمنا إحدى الدوال لمعرفة عدد الأيام التي مرّت منذ 01/01/1900 ودالتين أخريين لمعرفة تسلسل اليوم في الأسبوع وتسلسل الأسبوع في السنة. في الدرس القادم سنغطّي القسم الثاني من قائمة دوال Date & Time، وهي دوال الوقت الأساسية.
  5. يمكنك استخدام اكسل تماما كما تستخدم الحاسبة في إجراء العمليات الحسابية البسيطة والمعقدة. فهو يحتوي على مجموعة واسعة من الدوال functions الخاصة بمختلف المجالات يمكنك استخدامها لإجراء العمليات الحسابية المطولة في وقت قصير. الصيغ في اكسل هي عبارة عن مجموعة من المعاملات، الدوال والأرقام. يجب أن تبدأ أي صيغة بعلامة يساوي (=)، وسيتوضح المفهوم أكثر عن طريق الأمثلة في الفقرات التالية. الرياضيات الأساسية في اكسلتقوم معظم العمليات الحسابية المعقدة على أساس الرياضيات البسيطة؛ الجمع، الطرح، الضرب، والقسمة. لنتعلم كيفية القيام بهذه العمليات باستخدام المعاملات (+، -، *، /) أو الدوال (Sum، product، إلخ). افتح برنامج اكسل وقم بإنشاء جدول بيانات بسيط يحتوي على عدة أرقام لتطبيق العمليات الحسابية عليها. الجمعلكي تقوم بجمع رقمين أو عدد من الأرقام، حدّد الخلية التي تريد ظهور الناتج فيها ثم اكتب صيغة الجمع يدويا: =العدد الثاني + العدد الأول ثم اضغط Enter من لوحة المفاتيح. لكن هذه الطريقة ستصبح مطولة ومملة إذا كان عدد الأرقام التي تريد جمعها أكثر من 3. لذلك بدلا من كتابة الأرقام قم بتحديد الخلايا. أي اكتب علامة (=) ثم حدد الخلية الأولى بواسطة الفأرة، ثم علامة (+) ثم حدد الخلية الثانية، وهكذا. لاحظ أن البرنامج يقوم بتمييز الخلايا مع اسم الخلية في الصيغة بنفس اللون. هذه الطريقة مفيدة أكثر إذا كنت ستجري تغييرا على الجدول لاحقا، إذا سيتغير ناتج الجمع تلقائيا تبعا لتغير الأرقام في الخلايا المشمولة في الصيغة. أي إذا قمت بتغيير محتوى الخلية B5 من "3" إلى "5" ستتغير النتيجة إلى "14" تلقائيا. الطرحلا تختلف عملية الطرح عن عملية الجمع سوى باستخدام المعامل (-) بدلا من (+). يمكنك طرح مجموعة من الخلايا المتجاورة أو غير المتجاورة بنفس طريقة عملية الجمع. الضرب والقسمةعمليتا الضرب والقسمة لا تختلفان عن الجمع والطرح. استخدم علامة النجمة (*) (وليس x) لعملية الضرب، وعلامة (/) لعملية القسمة. طريقة كتابة الصيغة هي كما في عمليتي الجمع والطرح. تذكر أن تكتب علامة = قبل بداية أي صيغة. استخدام الدوال Functionsالدّوال هي عبارة عن صيغة معرفة مسبقا في البرنامج. تساعدك الدوال في اكسل على توفير الوقت حيث انها تختصر الكثير من الخطوات. دالة الجمعاستخدم زر الجمع التلقائي لجمع نطاق من الخلايا "المتجاورة" بدلا من تحديد كل خلية على حدة. الصيغة العامة لدالة الجمع هي: SUM(number;number,…)ويمثل "number" رقم محدد أو اسم خلية. حدد الخلية التي تريد ظهور الناتج فيها، ويجب أن تكون بعد نطاق الخلايا المتجاورة. مثلا إذا أردت جمع الأرقام في العمود B يجب أن أقوم بتحديد خلية أسفل نطاق الخلايا ضمن العمود B. وإذا أردت جمع الأرقام في الصف 3، يجب أن أقوم بتحديد خلية على يمين نطاق الخلايا في الصف 3 (أو على يسار نطاق الخلايا إذا كان اتجاه الورقة من اليسار إلى اليمين) وهكذا. سأقوم بجمع الأرقام في العمود B، بتحديد الخلية B8، الذهاب إلى تبويب الصفحة الرئيسية، ثم النقر على زر الجمع التلقائي AutoSum. أو حدد الخلية واضغط على اختصار الجمع التلقائي Alt+ =. ستتحول حدود نطاق الخلايا إلى إطار متقطع متحرك، وستظهر صيغة الجمع (Sum(B3:B7= في الخلية التي سيظهر فيها الناتج. اضغط Enter لإتمام العملية. في المثال تمثل النقطتين (:) نطاق من الخلايا. وهذه هي الصيغة العامة لجمع أرقام في نطاق من الخلايا المتجاورة. سأقوم أيضا بجمع نطاق الخلايا في الصف 4 وبنفس الطريقة: لاحظ أنني حصلت على النتيجة "8" من عملية الجمع، وليس "18"، والسبب أنّ أمر الجمع التلقائي يُطبق على الخلايا المتجاورة فقط. يمكنك استخدام دالة الجمع (وليس زر الجمع التلقائي) إذا كانت الخلايا غير متجاورة أيضا. حدد أي خلية تريد ظهور النتيجة فيها، واكتب SUM=. اضغط على المفتاح Ctrl وقم بتحديد العدد الذي تريده من الخلايا (أو نطاق الخلايا) مع الاستمرار بالضغط، ثم أغلق القوس. لاحظ أيضا أنني قمت بتحديد الخليتين B3، B5 ونطاق الخلايا C5:C7. اضغط Enter للحصول على النتيجة. أو بطريقة أخرى، استخدم دالة الجمع واكتب أسماء الخلايا التي تريد جمع محتوياتها يدويًا، افصل بين اسم خلية وآخر بفارزة منقوطة (;). ملاحظة: لمشاهدة محتوى الخلية (أي الصيغة) انقر بشكل مزدوج على الخلية، أو قم بتحديد الخلية وشاهد الصيغة من شريط الصيغة. لا تمتلك عملية الطرح دالة معرفة كما في الجمع، والطريقة الوحيدة لتنفيذ عملية الطرح هي باستخدام المعامل (-). يمكنك أن تطرح ناتج دالة جمع من ناتج دالة جمع آخر: دالة الضربدالة الضرب تشابه دالة الجمع من حيث طريقة العمل، فيما عدا أنها تقوم بضرب الأرقام بدلا من جمعها. وصيغة دالة الضرب هي: PRODUCT(number;number,…)ويمثل "number" رقم محدد أو اسم خلية. يمكنك استخدام دالة الضرب لإيجاد ناتج الضرب لمجموعة خلايا متجاورة أو غير متجاورة: أما عملية القسمة فحالها حال عملية الطرح لا تمتلك دالة معرفة، استخدم المعامل (/) لتنفيذ عملية القسمة. يمكنك قسمة ناتج دالة ضرب على ناتج دالة جمع مثلا: تتابع العمليات الحسابيةيستخدم اكسل التتابع المعروف لتنفيذ العمليات الحسابية، أي: الأقواس أولا، من الداخل إلى الخارج.الأسس.الضرب والقسمة من اليسار إلى اليمين.وأخيرا الجمع والطرح من اليسار إلى اليمين.أمثلة: =((25/5)+(2*3)) =5+6 =11=45/9*5 (تنفذ العمليات من اليسار إلى اليمين، أي القسمة أولا ثم الضرب) =5*5 =25=5-4+3 (تنفذ العمليات من اليسار إلى اليمين، أي الطرح أولا ثم الجمع) =1+3 =4=2+(3*(1+5)^2)-6/3 =2+(3*36)-2 =2+108-2 =108 في هذا المثال: يتم إيجاد نتيجة القوس الداخلي (1+5) =6ثم يرفع الناتج للأس (2) = 36 لأن الأسس تتبع الأقواس في تتابع العملياتثم تضرب النتيجة بالعدد (3) = 108ثم يتم إيجاد ناتج عملية القسمة (6/3) = 2بعدها تصبح الصيغة كالتالي: 2-108+2=والنتيجة النهائية = 108.جرّب تطبيق هذه الصيغ وصيغ أخرى لتفهم تتابع العمليات الحسابية بشكل أفضل. صيغ متقدمةيمكن أن تصبح الصيغ أكثر تعقيدا حسب طبيعة البيانات التي تعمل عليها. ويوفر اكسل مجموعة كبيرة من الدوال المعرفة التي يمكنك استخدامها لتبسيط عملك، كالدوال الهندسية، الدوال المنطقية، دوال الوقت والتاريخ، إلخ. يمكنك استخدام الدوال التي تتناسب ومجالك. للوصول إلى مجموعة الدوال اذهب إلى تبويب صيغ Formulas. انقر على زر المزيد من الدوال More Functions إذا لم تجد ما تبحث عنه. لنأخذ المثال التالي لتوضيح المزيد من القواعد المتعلقة بالصيغ والدوال: الجدول عبارة عن درجات مجموعة من الطلاب لاختبارات الفصلين الأول والثاني والاختبار النهائي. والهدف هنا هو إيجاد النتيجة النهائية بضرب كل درجة بنسبة الفصل، وجمعها للحصول على الدرجة النهائية لكل طالب. سأقوم أولا بتحويل نسبة الفصل إلى نسبة مئوية بتحديد نطاق الخلايا، ثم من تبويب الصفحة الرئيسية Home، ومن خانة أرقام Numbers انقر على زر %. في الخلية H11 سأقوم بإيجاد النتيجة النهائية للطالب 1، بكتابة الصيغة كما في الصورة أدناه: أي سيتم ضرب الدرجة الأولى x 20%، والدرجة الثانية x 20%، والدرجة الثالثة x 60%، ثم تجمع نتائج الضرب الثلاث. سأستخدم خيار التعبئة التلقائية AutoFill (أي نسخ الصيغة) لتكرير نفس الخطوة تلقائيا بدلا من كتابة الصيغة يدويا. لعمل تعبئة تلقائية انقر على الخلية التي تريد نسخ صيغتها، ضع المؤشر على المربع الأخضر في حافة الخلية ليتحول شكله إلى (+) ثم انقر مع السحب إلى جهة اليسار. لكن لاحظ النتائج التي حصلت عليها: تفسير الخطأ الذي حدث هنا هو أنه يوجد نوعان من المراجع للخلايا؛ المراجع النسبية relative references والمراجع المطلقة absolute references. ويستخدم اكسل المراجع النسبية في الصيغة بشكل افتراضي. عندما اخترت الخلية H11 لإظهار النتيجة كانت الصيغة كالتالي: =(G8*H8)+(G9*H9)+(G10*H10)وعندما استخدمت التعبئة لإظهار النتيجة في الخلية التالية إلى اليسار (I11) انتقل اكسل أيضا بالصيغة خطوة إلى اليسار، وأصبحت الصيغة في الخلية I11 كالتالي: =(H8*I8)+(H9*I9)+(H10*I10)أي انتقل من G8 إلى H8، ومن H8 إلى I8، وهكذا. أي أن النسب في الخلايا G8، G9، وG10 تم تجاوزها ولم يتم استخدامها. بمعنى أنه تم استخدام الخلايا G8، G9، وG10 كمرجع نسبي. لذلك يجب التبديل من المراجع النسبية إلى المراجع المطلقة (أي تثبيت الخلايا G8، G9، وG10 في الصيغة واستخدامها كمرجع مطلق) باستخدام المفتاح F4 عند تحديد قيمة الخلية المراد تثبيتها. لاحظ كيف تتغير الصيغة في الصورة أدناه (علامة الدولار $ تستخدم للمراجع المطلقة): وعندما أقوم بالتعبئة التلقائية هذه المرة ستظهر النتائج الصحيحة: جمع الوقت أو طرحهيمكنك إضافة الوقت في جداول بيانات اكسل كأي نوع آخر من البيانات وتنسيقه. كما يمكنك إجراء عمليتي الجمع والطرح عليه أيضًا. يُعرض الوقت في اكسل بعدة تنسيقات كالساعات والدقائق، الساعات والدقائق والثواني، الوقت صباحا (AM)/مساء (PM)، إلخ. يمكنك الوصول إلى هذه التنسيقات عن طريق النقر بزر الفأرة الأيمن على الخلية التي تحتوي على بيانات بصيغة الوقت ثم اختيار تنسيق الخلايا Format Cells. جمع الوقتقد تحتاج إلى جمع الوقت إذا كان لديك مشروع مقسم إلى مهام وتريد معرفة الزمن الكلي الذي يستغرقه إنجاز المشروع، كما في المثال التالي: سأقوم بتحديد الخلية C6 لإظهار نتيجة الجمع فيها ثم استخدم دالة الجمع التلقائي (أو كتابة الصيغة يدويا): ثم سأستخدم التعبئة التلقائية لتطبيق نفس الصيغة على بقية المشاريع بدلا من تكرار عملية الجمع على كل مشروع: سأكون بذلك قد انتهيت من جمع الوقت لولا نتيجة المشروع 3 غير المنطقية على الرغم من كون الصيغة صحيحة، فمن المستحيل أن يكون النتائج 3:55 عند جمع 20:30 ساعة مع 7:25. وتفسير ذلك هو أن نتيجة الجمع أكبر من 24 ساعة، والخلية غير منسقة لتعرض الوقت أكبر من 24 ساعة. لحل المشكلة، سنقوم بتنسيق الخلية لتعرض الوقت أكبر من 24 ساعة: انقر على الخلية بزر الفأرة الأيمن واختر تنسيق الخلايا Format Cellsمن قسم مخصص Custom وفي خانة النوع Type اكتب h]:mm] تستخدم الأقواس المربعة لعرض الوقت أكبر من 24 ساعة، ويمثل حرف h الساعات، وmm الدقائق. بعد كتابة الصيغة انقر موافق OK وستظهر النتيجة الصحيحة. تستطيع استخدام الأقواس المربعة في كل الحالات لتجنب حدوث مثل هذه الأخطاء. يمكنك أيضا إضافة مدة معينة من الوقت إلى وقت محدد باستخدام دالة الوقت، مثلا إذا كنت ترغب في إضافة ثلاث ساعات وربع إلى الساعة الخامسة والنصف مساء اكتب الصيغة التالية واضغط Enter. يمثل الرقم 3 عدد الساعات، الرقم 15 عدد الدقائق، والرقم 0 عدد الثواني. طرح الوقتيمكنك طرح الوقت أيضا باستخدام اكسل بنفس طريقة طرح الأرقام العادية، فيما عدا أنه لا يظهر النتائج السالبة. وكذلك يجب أن تستخدم المعامل (-) لعدم وجود دالة معرفة لعملية الطرح. قد تحتاج إلى طرح الوقت لمعرفة الوقت المستغرق لعمل يبدأ في وقت محدد وينتهي في وقت محدد، كما في المثال التالي: في الخلية التي تريد إظهار النتيجة فيها قم بكتابة الصيغة التالية (طرح وقت البدء من وقت الانتهاء): بعدها قم بعمل تعبئة تلقائية لتطبيق الصيغة على بقية الخلايا. لاحظ النتائج التالية: النتيجة الأولى على شكل مربعات (#) لأنها سالبة، أي وقت الانتهاء أقل من وقت البدء، وهذا بسبب خطأ في الإدخال (يجب أن يكون وقت الانتهاء مساء وليس صباحا). النتيجة الثانية خاطئة لأن تنسيق الخلية لا يظهر الوقت أكبر من 24 ساعة، وسنقوم بتصحيح هذا الخطأ بالنقر بزر الفأرة الأيمن على الخلية، اختيار تنسيق الخلايا Format Cells، ثم اختيار التنسيق الذي قمنا بعمله سابقا لإظهار الوقت أكبر من 24 ساعة (h]:mm]). النتيجة الثالثة صحيحة. إذا كنت ترغب بإظهار النتائج بصيغة أرقام اعتيادية وليس بصيغة وقت (أي 8.5 بدلا من 8:30) اتبع الخطوات التالية: حدد الخلية التي تريد إظهار الناتج فيها واكتب الصيغة التالية: قمنا باستخدام الأقواس لنتأكد من أن عملية الطرح تنفذ قبل عملية الضرب. كما قمنا بالضرب بالرقم 24 لأن الوقت مخزون في اكسل كجزء من اليوم. أي 6 ساعات تعرف في اكسل بربع يوم (0.25)، و12 ساعة تعرف بنصف يوم (0.5) يوم. لذلك استخدمنا الرقم 24 للتحويل من الجزء من اليوم إلى ساعات. بعد تنفيذ الصيغة انقر بزر الفأرة الأيمن على النتيجة، اختر تنسيق الخلايا Format Cells، ثم اذهب إلى قسم رقم Number. حدد عدد المراتب العشرية التي تريد إظهارها بعد الفارزة ثم انقر موافق OK. سيتحول الناتج من صيغة وقت إلى أرقام عشرية. وكما في عملية جمع الوقت، يمكنك أيضا طرح مدة معينة من الوقت من وقت محدد باستخدام دالة الوقت، مثلا إذا كنت ترغب في طرح ساعتين و45 دقيقة من الساعة التاسعة والربع صباحا اكتب الصيغة التالية واضغط Enter. يمثل الرقم 2 الساعات، الرقم 45 الدقائق، والرقم 0 الثواني.
  6. python 101

    إلى الآن، تعرفنا في هذه السلسلة من الدروس على أساسيات التعامل مع أنواع البيانات، المُتغيرات، الجمل الشرطية، وحلقات التكرار for و while. وقد أصبح لديك الآن المعلومات الكافية لبرمجة برامج مُتوسطة قد تحتوي على مئات الأسطر البرمجية، وقد حان الوقت لتتعرف على الدوال لكي تجعل مُهمة إعادة استخدام أجزاء من شيفرتك أكثر سهولة ومرونة، كما ستتعرف على بعض من الدوال المُعرفة مُسبقا في لغة بايثون. للتذكير: جميع الشّيفرات التّي تبدأ بعلامة <<< يجب أن تنفّذ على مفسر بايثون. الدوال الدّالة في البرمجة كاسم المتغيّر يُمكنك استدعاؤها عند الحاجة لكنّ المتغير لا يحمل سوى قيمة واحدة، أمّا الدّالة فتحمل شيفرة مستقلة وقد تكون هذه الشيفرة جملة شرطية أو جملة طباعة أو حلقة تكراريّة أو كل ما سبق. وتُستعمل الدوال أساسا لتجنب تكرار شيفرة عدة مرات، فمثلا لنقل بأنّك كتبت شيفرة للجمع بين عددين ثم بعد ذلك أردت أن تجمع عددين آخرين وهكذا، إذا حاولت تكرار الشيفرة سيكون الأمر مُتعبا جدا خاصة إذا كانت الشيفرة التي تكررها طويلة جدا، لذلك فلغات البرمجة توفر الدوال. لنعتبر بأنّ طباعة جملة "Hello" هي الشيفرة التّي تحملها الدّالة، انظر المثال التّالي: >>> def say_hello(): ... print "Hello" ... >>> say_hello() Hello أولا قمنا بإنشاء الدّالة say_hello في السّطر: def say_hello(): النّقاط الثّلاثة التّي تظهر بعد ذلك السّطر تعني بأن مُفسر بايثون ينتظر مدخلات أخرى، لذلك ندخل شيفرة الطّباعة (تذكر بأن هذه هي الشيفرة الأساسيّة) بعد مساحة بيضاء (أربع مسافات). بعد إنشاء الدّالة سيرجع المفسّر إلى حالته الطّبيعية، بدون أي مُخرجات، وذلك لأنّنا يجب أن نستدعي الدّالة لكي تُنفّذَ الشّيفرة التّي بداخلها، والاستدعاء يكون بكتابة اسم الدّالة مع قوسين: >>> say_hello() ما رأيناه قبل قليل هو كيفية تعريف دالة، كيفية وضع شيفرة داخلها ثم كيفية استدعائها لتنفذ الشيفرة. يُمكن أن نجعل الدالة تُعيد قيمة دون تنفيذ أي شيفرة (رغم أنّها تُنفذ شيفرة الإرجاع)، انظر المثال التالي: >>> def x(): ... return 4 ... >>> x() 4 ما فعلناه هو أنّنا قُمنا بجعل الدالة قيمة عوضا عن أن تُنفذ شيفرة ما، أي أنّنا استخدمنا الدالة x كمُتغير عادي يحمل قيمة مُحدّدة. قد تسأل نفسك، ما فائدة الأمر؟. الأمر مُفيد جدا إذا كان برنامجك كبيرا، بحيث يُمكنك استعمال الدوال كقيمة مُخرجة بعد عدة عمليات. مثلا، إذا كان لديك برنامج يطلب من المُستخدم مُدخلا (كاسمه أو كلمة مروره) وتُريد التحقق من مُدخله وإجراء عمليات عليه، فاستعمال المُتغيرات هنا ليست فكرة جيدة وذلك لأنّ الشيفرة ستكون صعبة التعديل. عوضا عن ذلك يُمكنك أن تقوم بالعمليات على المدخل داخل دالة ثم بعد ذلك تجعل الدالة تحمل القيمة التي ترغب بها في النهاية. ملاحظة حول تسمية الدوال رغم أنك تستطيع تسمية الدوال بأحرف صغيرة وكبيرة معا، من المُفضل تسمية الدالة بأحرف صغيرة والفصل بين كل كلمة والأخرى بمحرف "_". المعاملات Parameters من مُميزات الدوال أنّك تستطيع أن تُعطيها مُعاملات عند تعريفها، وأن تُعطي القيم لهذه المُعاملات إما عند تعريف الدالة (المعاملات الافتراضية) أو لاحقا. لتفهم أكثر، انظر المثال التالي: >>> def say_hello(name): ... print 'Hello', name ... >>> say_hello('Abdelhadi') Hello Abdelhadi >>> say_hello('Hsoub Academy') Hello Hsoub Academy كما ترى لقد قُمنا بتعريف الدالة say_hello مع مُعامل name ووضعنا داخلها جملة طباعة لتطبع Hello متبوعا بقيمة العامل name بعدها قُمنا باستدعاء الدالة وأسندنا للعامل name قيمتين مُختلفتين، وقد كانت النتائج مُختلفة، يُمكنك أن تستدعي نفس الدالة مع معاملات مُختلفة لعدد غير محدود من المرات. يُمكنك كذلك أن تقوم بتعريف دالة مع أكثر من معامل، إليك مثالا على دالة لإعادة مجموع عددين : >>> def add_numbers(n1, n2): ... return n1 + n2 ... >>> add_numbers(3,4) 7 إذا قُمنا بتعريف دالة مع معامل فلا بد أن نقوم بتعيين قيمة العامل عند الاستدعاء وإلا فسيرجع مُفسر Python خطأ كالتّالي: >>> say_hello() TypeError: say_hello() takes exactly 1 argument (0 given) الأمر نفسه يحدث إذا عينت عددا أكثر من العوامل المُفترض، مثلا أن تعطي للدالة say_hello مُعاملين أو أكثر. يُمكنك أن تقوم بوضع قيمة افتراضية لمُعامل في سطر تعريف الدالة: >>> def num(n1, n2 = 10): ... return n1 + n2 ... >>> num(3) 13 يُمكن أن تستعمل هذه الطريقة لعرض خطأ للمُستخدم إذا نسي إدخال المُعاملات. >>> def say_hello(name = '| Error! Check the line that calls the function'): ... print 'Hello', name ... >>> say_hello() Hello | Error! Check the line that calls the function يُمكنك كذلك أن تقوم بعدة عمليات مع الدوال، وإليك قائمة ببعض هذه العمليات: تعريف دالة داخل دالة أخرى بما أن الدوال عبارة عن أجزاء من الشيفرة فتستطيع أن تقوم بإنشاء دالة أخرى أو عدد من الدوال داخل الدالة الواحدة، انظر المثال التالي: >>> def say_hello(name): ... def hello(): ... return 'Hello ' ... print hello() + name ... >>> say_hello('Abdelhadi') Hello Abdelhadi كما ترى أعلاه القيمة Hello ما هي إلا القيمة التي أرجعتها الدالة hello المعرفة بداخل الدالة say_hello. استدعاء دالة داخل دالة أخرى هذا الأمر بسيط، فقط استدع الدالة داخل دالة أخرى وستعمل كلتا الدالتان عند استدعاء الدالة الأم: >>> def say_hello(name): ... print 'Hello', name ... >>> def print_hello(): ... say_hello('Abdelhadi') ... >>> print_hello() Hello Abdelhadi في المثال أعلاه قُمنا باستدعاء الدالة say_hello من داخل الدالة print_hello. إسناد دالة لمتغير تستطيع أن تُنشئ دالة وتقوم بإسنادها لمُتغير بالطّريقة التالية: >>> def say_hello(name): ... print 'Hello', name ... >>> s = say_hello >>>> s('Abdelhadi') Hello Abdelhadi إسناد دالة كمعامل لدالة أخرى قلنا مُسبقا بأنّه يمكن للدالة أن تتصرف كمتغير وذلك عندما نجعلها ترجع قيمة بالجملة return. وهذا يعني بأنّنا نستطيع أن نسند للدالة دالة أخرى. >>> def say_hello(name): ... print 'Hello', name ... >>> def get_name(): ... return 'Abdelhadi' ... >>> say_hello(get_name()) Hello Abdelhadi إرجاع دالة داخل دالة أخرى يُمكنك أيضا أن تستعمل الجملة return لإرجاع دالة داخل دالة أخرى عوضا عن إرجاع قيمة ما، انظر المثال: >>> def get_hello(): ... return 'Hello Abdelhadi' ... >>> def say_hello(): ... return get_hello() ... >>> print say_hello() Hello Abdelhadi ستلاحظ بأنّ الدالة say_hello تحمل قيمة الدالة get_hello، وذلك لأنّنا أرجعنا هذه الأخيرة داخل الدالة say_hello. إسناد عدد لا نهائي من المعاملات لدالة ما لنقل بأنّك تريد أن تقوم بإنشاء دالة تطبع جميع المُحتويات (المُعاملات) التي تُدخلها دون الحاجة إلى تحديد كل معامل على حدة. يُمكنك أن تقوم بالأمر بما يُسمى مُعامل طول المُتغير أو Variable-length argument وذلك كالتالي: >>> def print_arguments(*args): ... print args ... >>> print_arguments(2, 4, 8, 'Abdelhadi', 'Hsoub Academy') (2, 4, 8, 'Abdelhadi', 'Hsoub Academy') المُتغير args عبارة عن صف (Tuple) من القيم، وبالتالي فإنك تستطيع أن تتعامل معه بحلقة For. يُمكن أن تستخدم أي اسم نريده لهذا المعامل، وعموما يعتبر الاسم args* تقليدا بين مُبرمجي بايثون. لاحظ أن الاختلاف بين المعامل العادي والمعامل في المثال أعلاه هو النجمة في البداية. تستطيع أن تجعل المُعاملات قاموسا عوضا عن صف بحيث تُرجع الدالة القاموس الذي يحتوي على اسم المعامل وقيمته، وذلك كالآتي: >>> def print_keyword_args(**kwargs): ... print kwargs ... >>> print_keyword_args(name = 'Abdelhadi', website = 'Hsoub Academy', n = 3) {'website': 'Hsoub Academy', 'name': 'Abdelhadi', 'n': 3} لاحظ بأنّ اسم المُعامل يبدأ بنجمتين هذه المرة، وهذا النوع من المُعاملات يسمى مُعاملات الكلمة المفتاحية Keyword Arguments لأنها ترجع قاموسا مفاتيحه هي أسماء المعاملات التي تختارها أنت وقيم المفاتيح هي قيم المعاملات. المتغيرات المحلية والمتغيرات العامة Local variables and Global variables المتغيرات المحلية هي المتغيرات التي نقوم بإنشائها داخل دالة، أما المتغيرات العامة فهي التي ننشئها خارج الدالة. يُمكنك أن تصل إلى المتغيرات العامة في أي مكان من برنامجك، على خلاف المُتغيرات المحلية التي ستتمكن من الوصول إليها فقط داخل الدالة، انظر المثال التالي: >>> def say_hello(): ... name = 'Abdelhadi' ... print 'Hello', name ... >>> say_hello() Hello Abdelhadi >>> print name Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'name' is not defined قُمنا بتعريف المُتغير name داخل الدالة say_hello وبعدها حاولنا الوصول إليه خارج الدالة، ما أدى إلى خطأ مفاده بأن مُفسر بايثون لم يتعرف على المُتغير. يُمكن أن نجعل المتغير name عامًا بإضافة الكلمة global قبله (عليك أن تقوم بهذا قبل إسناد قيمة للمُتغير)، انظر المثال التالي: >>> def say_hello(): ... global name ... name = 'Abdelhadi' ... >>> say_hello() >>> print name Abdelhadi نُلاحظ بأنّنا استطعنا الوصول إلى المُتغيّر name خارج الدالة التي عُرّفَ بها. تطبيق سنضرب مثالا بالبرنامج الذي أنشأناه في درس التعابير الشرطية والإزاحات. print 'Hello User, this is a basic sign up/login Program' username = raw_input('Enter your username please: ') password = raw_input('Enter the your password please: ') password_verification = raw_input('Verify password: ') if password == password_verification: print 'You have Successfully Signed up! \n' username_sign_in = raw_input('Enter your username please: ') password_sign_in = raw_input('Enter your password please: ') if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' else: print 'The password and the password verification do not match! Please try again' سنركز على شيفرة التحقق من المُستخدم وكلمة المرور: if username_sign_in == username and password_sign_in == password: print 'You have Successfully Signed in!' else: print 'username or password do not match! Please try again!' إذا أردنا أن نستخدمها لأكثر من مرة في برنامجنا فعلينا أن نضعها داخل دالة. def user_logged_in?(username_sign_in, username, password_sign_in, password): if username_sign_in == username and password_sign_in == password: return True else: return False يُمكنك استخدام الدالة في أي مكان من الشيفرة: def is_user_logged_in(username_sign_in, username, password_sign_in, password): if username_sign_in == username and password_sign_in == password: return True else: return False new_password = raw_input('Enter new username: ') new_username = raw_input('Enter new password: ') print 'Ok!' password = raw_input('Hello again, Enter your username: ') username = raw_input('Enter username\'s password: ') print is_user_logged_in(username, new_username, password, new_password) الدالة is_user_logged_in تقوم بمُقارنة كلمتي المرور واسمي المُستخدم فإن كانا متطابقين فستصبح قيمة الدالة True أما إن لم تتوافق القيم فإنّ الدالة تحمل القيمة False ويُمكنك الآن استخدام الدالة مع الجمل الشرطية في أي مكان من برنامجك دون الاضطرار لإعادة كتابة شيفرة التحقق كل مرة. كما أنّ التعديل على الشيفرة بسيط جدا، فالتّعديل من مكان واحد (الدالة) يكفي يطبّق على جميع الأماكن الأخرى (أمكنة استدعاء الدالة). الدوال المعرفة مسبقا تُوفر بايثون دوالا مُعرفة مُسبقا، وقد تعاملنا مع كثير منها في الدروس السابقة، وإليك بعض الدوال المُفيدة التي توجد مُسبقا بلغة بايثون. print: دالة الطّباعة التي استخدمناها أكثر من مرة لطباعة القيم في سابق الدروس. Int: دالة تحويل القيم إلى عدد صحيح، مثال: >>> int(5.5) 5 str: دالة تحويل القيم إلى سلسلة نصيّة String: >>> str(True) 'True' وتُستعمل كثيرا لجمع سلسلة نصية بقيمة من نوع آخر بالعامل + (إذا لم تستخدم هذه الدالة فسيعرض لك مُفسر بايثون خطأ يُفيد بأنّك لا تستطيع جمع قيمتين من نوعين مُختلفين): >>> print 'ABC' + str(122) + str(False) ABC122False abs: دالة للحصول على القيمة المُطلقة Absolute Value لعدد ما (إذا كان موجبا فهو العدد نفسه، وإذا كان سالبا فمُقابله): >>> abs(3) 3 >>> abs(-3) 3 len: دالة لقياس عدد عناصر قائمة أو عدد أحرف سلسلة نصية. >>> a = ['Abdelhadi', 'Dyouri', 'Academy', 'Hsoub'] >>> b = 'Hello' >>> len(a) 4 >>> len(b) 5 min: دالة لتحديد أقل قيمة بين قيمتين أو أكثر. >>> min(4, 5, 7, 88, 3, 2) 2 max: دالة لتحديد أقل قيمة بين قيمتين أو أكثر. >>> max(4, 5, 7, 88, 3, 2) 88 range: لتوليد قائمة بأعداد بين قيمة المعامل الأول وقيمة المُعامل الثاني: >>> range(0, 11) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> range(0, 11, 3) [0, 3, 6, 9] raw_input: دالة للحصول على مُدخل نصي من المُستخدم، يُمكنك أن تسند هذا المُدخل إلى مُتغير. >>> def say_hello(name): ... print 'Hello', name ... >>> say_hello(raw_input()) Abdelhadi Hello Abdelhadi كما قُلنا سابقا، فإنك تستطيع أن تقوم بإسناد دالة كمعامل لدالة أخرى، وهذا ما فعلناه في المثال أعلاه، إذ مررنا الدالة raw_input ليكون معاملا للدالة say_hello. تمارين تمرين 1 اكتب برنامجا للحصول على قيمة من المُستخدم وتحويلها إلى قيمة عددية. تمرين 2 اكتب دالة لطباعة جملة لعدد من المرات، واترك للمُستخدم حرية اختيار عدد مرات التكرار (مُساعدة: استعمل الدالة raw_input للحصول على قيمة من المُستخدم) تمرين 3 اكتب دالة للجمع بين عددين يُدخلهما المُستخدم. تمرين 4 بَرمِجْ آلة حاسبة بسيطة تقوم بالجمع، الطّرح، الضرب والقسمة. إليك طريقة العمل: احصل على قيمة العدد الأول من المُستخدم. احصل على قيمة العدد الثاني. حول القيمتين النصيتين إلى قيمتين عدديتين. احصل على العامل الرياضي (*، /، - أو +) من المُستخدم. استخدم الجمل الشرطية لإجراء العملية المُناسبة (إذا كان المُدخل + فقم بالجمع). ترجمة -وبتصرف- من الكتاب Python Practice Book لكاتبه Anand Chitipothu.
  7. عندما يزداد طول البرامج وتعقيدها، فستزداد صعوبة تصميمها وبرمجتها وصيانتها؛ لذا من المفيد عادةً تقسيم المهام الكبيرة إلى سلسلة من المهام الأصغر. سنُقسِّم في هذا الدرس السكربت الذي كنا نعمل عليه إلى عدد من الدوال (functions) المنفصلة. لكي نتعرف على مفهوم الدوال، فلنحاول وصف طريقة القيام بمهمة يومية: الذهاب إلى السوق وشراء الطعام. تخيل أننا سنصف العملية إلى كائنات فضائية آتية من المريخ. سيبدو الوصف العام لعملية شراء الطعام كالآتي: غادر المنزل قد السيارة إلى السوق اركن السيارة ادخل السوق اشترِ طعامًا قد السيارة إلى المنزل اركن السيارة ادخل إلى المنزل سيُغطِّي الشرح السابق الآلية العامة للذهاب إلى السوق؛ لكن تلك الكائنات الفضائية ستحتاج مزيدًا من التفاصيل، فمثلًا يمكن وصف المهمة الفرعية "اركن السيارة" كالآتي: اعثر على مكان فارغ لركن السيارة قد السيارة إلى ذاك المكان أطفئ المحرك "ارفع" المكابح اليدوية اخرج من السيارة اقفل السيارة ويمكن بالطبع تقسيم خطوة "أطفئ المحرك" إلى عدد من الخطوات مثل: أطفئ دارة الإشعال أخرج مفتاح السيارة وهكذا إلى أن تُفصِّل كل خطوة من كامل عملية الذهاب إلى السوق. عملية تعريف الخطوط الأساسية ومن ثم كتابة التفاصيل لتلك الخطوات تسمى "نمط تصميم Top-Down". يسمح هذا النمط لنا بتقسيم المهام الكبيرة والضخمة إلى مهام أبسط وأصغر. سنستخدم نمط تصميم Top-Down ليساعدنا في التخطيط لبرنامجنا الذي سنكمل تطويره وإضافة الميزات إليه. يمكننا تلخيص "الوصف العام" للمهام التي يقوم بها السكربت الآن: بداية الصفحة بداية ترويسة الصفحة كتابة العنوان إغلاق الترويسة بداية جسم الصفحة كتابة العنوان كتابة بصمة الوقت (timestamp) إغلاق الجسم إغلاق الصفحة تمت برمجة كل الخطوات السابقة، لكننا نريد إضافة المزيد. لندرج بعض المهام الإضافية بعد المهمة السابعة: كتابة بصمة الوقت كتابة معلومات عن إصدار النظام كتابة الوقت الذي مضى منذ آخر تشغيل (uptime) كتابة مساحة القرص كتابة المساحة التخزينية لمجلدات المنزل (home) إغلاق الجسم إغلاق الصفحة سيكون من حسن حظنا وجود أوامر تستطيع تنفيذ المهام الإضافية، فسنستطيع استخدام "تعويض الأوامر" (command substitution) لوضعها في السكربت كالآتي: #!/bin/bash # sysinfo_page - A script to produce a system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ أما للمهام التي لا توجد أوامر تستطيع فعل ما نريد تحديدًا، فيمكننا إنشاؤها باستخدام دوال الصدفة (shell functions). وكما تعلمنا في أحد الدروس السابقة، يمكن اعتبار دوال الصدفة على أنها "برامج صغيرة ضمن البرامج" وتسمح لنا باتباع مبادئ نمط التصميم top-down. علينا تعديل السكربت كالآتي لإضافة دوال الصدفة: #!/bin/bash # sysinfo_page - A script to produce an system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Functions system_info() { } show_uptime() { } drive_space() { } home_space() { } ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ هنالك نقطتان تجدر الإشارة إليهما: أولهما أنَّه يجب تعريف دوال الصدفة قبل محاولة استخدامها؛ وثانيهما هو أنَّ جسم الدالة (أي القسم الذي يقع بين قوس البداية "}" وقوس النهاية "{") يجب أن يحتوي على أمرٍ واحدٍ على الأقل. لن يعمل السكربت السابق وسيُظهِر رسالة خطأ وذلك لأنَّ جسم الدوال فارغ. أبسط طريقة لتصحيح هذه المشكلة هي وضع عبارة "return" في جسم كل دالة، وبعدها سيُنفَّذ السكربت بنجاح. إبقاء السكربتات قابلة للتشغيل من المفيد أثناء تطويرنا للتطبيق أن نُضيف جزءًا يسيرًا من الشيفرات ثم نُجرِّب السكربت ثم نضيف المزيد ثم نجرِّب السكربت وهكذا. وبهذه الطريقة سيسهل العثور على الأخطاء في الشيفرة ومن ثم تصحيحها. بعد إضافة الدوال إلى السكربت، أصبح بإمكانك الآن مراقبة التسلسل المنطقي لتنفيذ السكربت وذلك عبر آلية يُطلَق عليها اسم stubbing أي إضافة شيفرة وهمية. يمكنك تخيل هذه الآلية كما يلي: لنفترض أننا نريد إنشاء دالة اسمها "system_info" لكننا لم نفكر في تفاصيل الشيفرة بشكل كامل. فبدلًا من إيقاف عملية تطوير السكربت إلى أن ننتهي من الدالة system_info فيمكننا إضافة الأمر echo إليها كالآتي: system_info() { # Temporary function stub echo "function system_info" } سنتمكن باستخدام هذه الآلية من تنفيذ السكربت دون خطأ حتى لو لم نكمل برمجة الدالة system_info؛ ونستطيع لاحقًا وضع الشيفرة الحقيقية بدلًا من أمر echo السابق. سبب استخدامنا لأمر echo هو أننا نحتاج إلى مؤشر لكي نعرف أنَّ السكربت قد نفَّذ الدالة المعنية. لنُطبِّق هذه الآلية على جميع الدوال في السكربت: #!/bin/bash # sysinfo_page - A script to produce an system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Functions system_info() { # Temporary function stub echo "function system_info" } show_uptime() { # Temporary function stub echo "function show_uptime" } drive_space() { # Temporary function stub echo "function drive_space" } home_space() { # Temporary function stub echo "function home_space" } ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ سنكمل الآن العمل على كل دالة على حدة لكي تُخرِج معلوماتٍ مفيدةً. show_uptime ستُظهِر الدالة show_uptime ناتج الأمر uptime، الذي يعرض عدِّة معلومات مثيرة للاهتمام حول النظام، بما في ذلك المدة الزمنية منذ آخر إعادة تشغيل، وعدد المستخدمين، والحِمل (load) الحالي على النظام. $ uptime 9:15pm up 2 days, 2:32, 2 users, load average: 0.00, 0.00, 0.00 لعرض ناتج الأمر uptime في صفحة HTML، فسنحتاج إلى برمجة دالة الصدفة كالآتي (وذلك بعد حذف الشيفرة الوهمية التي كانت فيها): show_uptime() { echo "<h2>System uptime</h2>" echo "<pre>" uptime echo "</pre>" } كما ترى، تُخرِج الدالة السابقة نصًا يحتوي على خليطٍ من وسوم HTML مع مخرجات الأمر uptime؛ وستصبح هذه المخرجات جزءًا من here script عندما تُجرى عملية "تعويض الأوامر" في الجزء الرئيسي من السكربت. drive_space تستخدم الدالة drive_space الأمر df لتوفير ملخص للمساحة التخزينية المستهلكة من أنظمة الملفات الموصولة (mounted file systems). $ df Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda2 509992 225772 279080 45% / /dev/hda1 23324 1796 21288 8% /boot /dev/hda3 15739176 1748176 13832360 12% /home /dev/hda5 3123888 3039584 52820 99% /usr ستبدو بنية دالة dive_space شبيهةً للغاية بدالة show_uptime: drive_space() { echo "<h2>Filesystem space</h2>" echo "<pre>" df echo "</pre>" } home_space ستُظهِر دالة home_space مقدار المساحة التخزينية التي يستهلكها كل مستخدم في مجلد المنزل الخاص به. سيُعرَض الناتج كقائمة مرتبة تنازليًا وفق مقدار المساحة التخزينية المستخدمة. home_space() { echo "<h2>Home directory space by user</h2>" echo "<pre>" echo "Bytes Directory" du -s /home/* | sort -nr echo "</pre>" } لاحظ أنَّه يجب تنفيذ السكربت عبر مستخدم يملك امتيازات إدارية لكي تعمل الدالة السابقة بشكلٍ صحيح، لأنَّ الأمر du يتطلب امتيازات الجذر (root) لكي يتفحص محتويات المجلد ‎/home. system_info لسنا جاهزين بعد لإكمال دالة system_info. لكننا سنُحسِّن من الشيفرة الوهمية التي فيها لكي تُنتِج وسوم HTML: system_info() { echo "<h2>System release info</h2>" echo "<p>Function not yet implemented</p>" } ترجمة -وبتصرّف- للمقالَين Shell Functions و Some Real Work لصاحبهما William Shotts.
  8. قبل أن تبدأ في كتابة سكربتات جديدة، عليّ أن أشير إلى أنَّك تملك بعض السكربتات الموجودة مسبقًا، وضِعَت هذه السكربتات في مجلد المنزل الخاص بك عندما أُنشِئ حسابك، وتُستعمل لضبط سلوك جلسات سطر الأوامر في حاسوبك؛ تستطيع تعديل هذه السكربتات لتغيير بعض الأمور. سنلقِي نظرةً على سكربتَين من هذه السكربتات في هذا الدرس لكي نتعلم بعض المفاهيم الجديدة والمهمة عن الصَدَفة. يُبقي النظام على مجموعة من المعلومات حول جلستك تدعى "البيئة" (environment)، تحتوي البيئة على أشياء مثل المجلدات التي سيتم البحث فيها عن البرمجيات (PATH)، واسم المستخدم، واسم الملف الذي سيُحفَظ فيه بريدك الإلكتروني، وغير ذلك. يمكنك رؤية قائمة كاملة لضبط البيئة بالأمر set. هنالك نوعان من الأوامر التي تحتويها البيئة، وتُعرَف بالاختصارات (aliases) ودوال الصّدفة (shell functions). ما هو منشأ البيئة؟ تبدأ صَدَفة bash عندما تُسجِّل دخولك إلى النظام، وتقرأ سلسلة من ملفات الضبط تُسمى "ملفات بدء التشغيل" أو "ملفات البدء" (startup files) التي تُعرِّف البيئة الافتراضية التي يتشارك فيها جميع المستخدمين؛ ثم ستقرأ ملفات بدء إضافية موجودة في مجلد المنزل الخاص بك التي تُعرِّف بيئتك الشخصية. يختلف الترتيب بحسب نوع جلسة سطر الأوامر التي بدأتها، إذ أنَّ هنالك نوعان: جلسة تحتاج إلى تسجيل دخول (login shell session) وجلسة لا تحتاج إلى تسجيل دخول (non-login shell session). الجلسة التي تحتاج إلى تسجيل دخول هي الجلسة التي تسألك عن اسم المستخدم وكلمة المرور، وذلك عندما تستعمل إحدى الطرفيات الوهمية (virtual console) على سبيل المثال. أما الجلسات التي لا تحتاج إلى تسجيل دخول فهي تحدث عادةً عندما تُشغِّل محاكي الطرفية داخل الواجهة الرسومية. تقرأ الصَدَفة التي تحتاج إلى تسجيل دخول ملف بدء أو أكثر كما هو موضَّح هنا: ‎/etc/profile: سكربت الضبط العام الذي يُطبَّق على جميع المستخدمين. ‎~/.bash_profile: ملف بدء خاص بالمستخدم، يمكن أن يُستعمل لضبط خياراتٍ أخرى غير موجودة في سكربت الضبط العام، أو لتجاوز بعضها وإعادة تعريفها. ‎~/.bash_login: إن لم يكن الملف ‎~/.bash_profile موجودًا فستحاول الصَدَفة bash قراءة هذا السكربت. ‎~/.profile: إن لم يكن الملف ‎~/.bash_profile أو ‎~/.bash_login موجودًا فستحاول الصَدَفة bash قراءة هذا الملف. هذا هو السلوك الافتراضي في التوزيعات المبنية على دبيان مثل أوبنتو. أما الصَدَفة التي لا تحتاج إلى تسجيل دخول، فتقرأ ملفات البدء الآتية: ‎/etc/bash.bashrc: سكربت ضبط عام يُطبَّق على جميع المستخدمين. ‎~/.bashrc: ملف بدء خاص بالمستخدم، يمكن أن يُستعمل لضبط خياراتٍ أخرى غير موجودة في سكربت الضبط العام، أو لتجاوز بعضها وإعادة تعريفها. إضافةً إلى قراءة ملفات الضبط السابقة، ترث الجلساتُ التي لا تحتاج إلى تسجيل دخول البيئةَ من العملية الأب (parent process) التي تكون عادةً جلسة تحتاج إلى تسجيل دخول. ألقِ نظرةً على نظامك لترى ما هي ملفات البدء التي عندك، لكن لاحظ أنَّ أغلبية الملفات السابقة تبدأ بنقطة (مما يعني أنها مخفية)، لذا عليك استخدام الخيار ‎-aمع الأمر ls. ls -a ملف ‎~/.bashrc هو أهم ملف بدء من وجه نظر المستخدم العادي لأنه يُقرَأ دائمًا. حيث تقرأه الجلسات التي لا تحتاج إلى تسجيل دخول افتراضيًا، وأغلبية ملفات البدء الخاصة بالجلسات التي تحتاج إلى تسجيل دخول تقرأ ملف ‎~/.bashrc أيضًا. إذا ألقيت نظرةً داخل ملف ‎.bash_profile‎ (الملف الآتي مأخوذ من توزيعة CentOS)، فسيبدو شبيهًا بالآتي: # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin export PATH تذكَّر أنَّ الأسطر التي تبدأ برمز # هي تعليقات ولا تُفسَّرها الصَدَفة؛ حيث أُضيفت هذه الأسطر لشرح الشيفرة لمن يقرأها من البشر. ستجد في السطر الرابع أول الأشياء المثيرة للاهتمام: if [ -f ~/.bashrc ]; then . ~/.bashrc fi هذه هي عبارة if الشرطية، التي سنشرحها بالتفصيل في درسٍ لاحق، لكنني سأفسرها لك كالآتي: إذا كان الملف ‎~/.bashrc موجودًا، فنفِّذ محتويات ‎~/.bashrc. يمكننا أن نرى أنَّ الشيفرة القصيرة السابقة هي التي تجعل الجلسات التي تحتاج إلى تسجيل الدخول تقرأ محتويات الملف ‎.bashrc. الخطوة التالية في ملف البدء هي ضبط المتغير PATH وإضافة ‎~/bin إلى قائمة المجلدات التي سيتم البحث فيها عن الملفات التنفيذية للأوامر. وفي نهاية الملف: export PATH وظيفة الأمر export هي إخبار الصَدَفة أنَّ عليها جعل محتويات المتغير PATH متاحةً للعمليات التي تنحدر منها (الأبناء). الاختصارات aliases الاختصارات (aliases) هي طريقة سهلة لإنشاء أمر جديد يعمل اختصارًا لأمرٍ أطول. لها الشكل العام الآتي: alias name=value حيث name هو اسم الأمر الجديد و value هي السلسلة النصية التي ستُنفَّذ عند إدخال name في سطر الأوامر. لنُنشِئ اختصارا اسمه l (حرف L صغير) ولنجعله اختصارًا للأمر ls -l (أي عرض محتويات المجلد بالصيغة التفصيلية). تأكَّد أنَّ مجلد العمل الحالي هو المنزل، ثم افتح ملف ‎.bashrc باستخدام محررك النصي المُفضَّل وأضف السطر الآتي إلى نهاية الملف: alias l='ls -l' عند إضافتك للأمر alias إلى الملف، فستُنشِئ أمرًا جديدًا اسمه l الذي يكافئ ls -l. أغلِق جلسة الطرفية الحالية وابدأ واحدة جديدة لتجربة الاختصار التي أنشأناه، وذلك لإعادة قراءة محتويات الملف ‎.bashrc. يمكنك باستخدام هذه التقنية إنشاء أي عدد من الاختصارات المُخصصة لاستعمالك الشخصي، هذه إحداها: alias today='date +"%A, %B %-d, %Y"' سيُنشِئ السطر السابق اختصارا جديدا اسمه today الذي سيُظهِر تاريخ اليوم بتنسيقٍ جميل. بالمناسبة، الأمر alias هو أمر مُضمَّن في الصَدَفة (shell builtin)، أي أنَّك تستطيع إنشاء الأوامر البديلة مباشرةً من سطر الأوامر؛ لكن يجب أن تعلم بأنَّ تلك الأوامر ستزول عند إغلاقك لجلسة الطرفية الحالية. مثال: $ alias l='ls -l' دوال الصدفة ستستفيد من أمر alias عند إنشاء اختصارات لأوامر بسيطة، لكن ماذا لو أردت إنشاء شيءٍ أكثر تعقيدًا؟ عليك حينها أن تجرِّب شيئًا يسمى "دوال الصدفة" (shell functions)، التي يمكنك اعتبارها أنهَّا "سكربتات داخل سكربتات"، أو سكربتات فرعية صغيرة. لنجرب واحدةً منها! افتح ملف ‎.bashrc بمحررك وضع ما يلي بدلًا عن الاختصار today: today() { echo -n "Today's date is: " date +"%A, %B %-d, %Y" } صدِّق أو لا تصدِّق، () هو أمر مضمَّن بالصدفة أيضًا مثَلُهَ كَمَثَلِ الأمر alias، حيث يمكنك أيضًا إدخال دوال الصدفة مباشرةً من سطر الأوامر. $ today() { > echo -n "Today's date is: " > date +"%A, %B %-d, %Y" > } $ لكن تلك الدوال -مثلما هو عليه الحال مع الأمر alias- ستزول عند إغلاق جلسة الطرفية الحالية. ترجمة -وبتصرّف- للمقال Editing The Scripts You Already Have لصاحبه William Shotts.
  9. دالتا VLOOKUP و HLOOKUP هي إحدى دوال البحث والإشارة Lookup and Reference وهي تُستخدم للبحث عن قيمة محددة في صف أو عمود، ومن ثم إرجاع قيمة معيّنة في الموضع نفسه من الصف أو العمود الثاني. سنتعرّف في هذا الدرس على هاتين الدالتين وكيفية استخدامهما. VLOOKUP اسم هذه الدالة هو اختصار لـ "Vertical Lookup" (البحث العمودي) وهي تُستخدم للبحث في عمود محدد عن قيمة محددة حسب الصفوف، وعند العثور على تلك القيمة تقوم بإرجاع ما يقابلها في العمود الثاني (الذي نقوم بتحديده في الصيغة أيضًا). يمكنك تشبيه عمل هذه الدالة بدليل الهاتف، حيث تقوم بالبحث عن رقم شخص محدد بالبحث عن اسمه أولا في عمود الأسماء، وعندما تجد الاسم المطلوب تعثر على الرقم الذي يقابله في العمود الثاني (عمود الأرقام). البناء العام لصيغة الدالة VLOOKUP (lookup_value; table_array; col_index_num; [range_lookup]) lookup_value: القيمة التي تريد البحث عنها. يجب أن تكون هذه القيمة موجودة في العمود الأول لنطاق الخلايا الذي نحدده في table_array. هذا المُعطى argument وجوده ضروري في الصيغة. table_array: ويمثل نطاق الخلايا الذي يحتوي البيانات التي تبحث فيها الدالة. وهذا المعطى وجوده ضروري أيضًا. col_index_num: رقم العمود في نطاق الخلايا table_array الذي يحتوي على القيمة التي سيتم إرجاعها. وجوده مطلوب في الدالة. range_lookup: هذا المعطى هو عبارة عن قيمة منطقية logical تحدد من خلالها فيما إذا كنت تريد من دالة VLOOKUP البحث عن تطابق تام (بإدخال القيمة FALSE) أو تطابق تقريبي (بإدخال القيمة TRUE) مع قيمة lookup_value، ووجوده اختياري في الصيغة. ملاحظة: عند استخدام القيمة المنطقية TRUE يجب أن يكون العمود الأول في نطاق الخلايا table_array مرتبا تصاعديا لكي يتم إرجاع قيمة صحيحة. مثال 1 الجدول أدناه يحتوي على بيانات الموظفين لشركة ما. عدد صفوف الجدول هو 100 صف تقريبا. في مثل هذه الجداول الكبيرة (وما يفوقها) قد يكون من المضيعة للوقت البحث في كل صف من صفوف الجدول إذا رغبنا في العثور على معلومة معينة. وسيكون الأمر أسهل وأسرع بكثير باستخدام دالة VLOOKUP. المطلوب هنا هو العثور على قسم ومقدار راتب الموظف صاحب البطاقة رقم 100، والموظف صاحب البطاقة رقم 65. نضع المؤشر في الخلية التي نريد إرجاع القيمة الأولى فيها، وهي الخلية H2 في هذا المثال، ثم نذهب إلى تبويب: صيغ Formulas > بحث وإشارة Lookup & Reference > VLOOKUP في مربع الحوار Function Arguments نقوم بتحديد معطيات الدالة: في الحقل الأول، lookup_value، نحدد القيمة التي نريد البحث عنها، وهي رقم البطاقة "100" في هذا المثال، لذلك سنحدد الخلية G2 التي تحتوي هذه القيمة. في الحقل الثاني، table_array، نحدد نطاق الخلايا الذي يحتوي بياناتنا. في هذا المثال سنحدد الجدول بأكمله (A1:D100). في الحقل الثالث، col_index_num، ندخل رقم العمود الذي يحتوي على القيمة التي سيتم إرجاعها، وبما إننا نريد العثور على "قسم" الموظف، فسنقوم بإدخال الرقم "3"، وهو تسلسل عمود "القسم" في الجدول من اليمين إلى اليسار (أي أنّ تسلسل عمود "رقم بطاقة الموظف هو"1"، عمود "تاريخ التوظيف" هو "2"، وهكذا). إذا كان اتجاه الورقة من اليسار إلى اليمين نقوم بحساب رقم العمود من اليسار إلى اليمين. في الحقل الرابع، range_lookup، نقوم بإدخال الرقم صفر (والذي يعني القيمة المنطقية FALSE) لأننا نبحث عن تطابق تام مع الرقم "100"، وليس تطابق تقريبي، بسبب وجود أرقام قريبة من رقم "100" في عمود "رقم بطاقة الموظف". ننقر على OK، وسيتم العثور على قسم صاحب البطاقة رقم 100 فورا، وهو قسم "الخدمات": تفسير عمل الصيغة تقوم الصيغة أولا بالبحث في صفوف عمود "رقم بطاقة الموظف" واحدا تلو الآخر، وعندما تعثر على الرقم "100" تقوم بإيجاد القيمة التي تقابلها في عمود "القسم" ثم ترجع هذه القيمة في الخلية H2. نكرر نفس الخطوات للعثور على مقدار راتب الموظف صاحب البطاقة رقم "100"، وستكون المعطيات كما موضّح في الصورة التالية: قمنا بإدخال الرقم "4" في الحقل الثالث لأنّ تسلسل عمود "الراتب" في الجدول هو الرابع. وكما في الخطوة السابقة، يتم إيجاد النتيجة في الخلية G2: الخطوات نفسها تنطبق على رقم البطاقة "65". مثال 2 الجدول أدناه يحتوي على درجات اختبارين لمجموعة من الطلاب، مع متوسط الدرجات. المطلوب هو إيجاد تقدير كل طالب باستخدام دالة VLOOKUP: بالتأكيد يمكننا إدخال التقديرات يدويا لكل طالب اعتمادًا على قيمة المتوسط، لكن كما ذكرنا، تسّهل دالة VLOOKUP العمل وتختصر الكثير من الوقت. ملاحظة: قمنا بترتيب القيم في عمود "الدرجة" (وهو العمود الأول من نطاق الخلايا table_array) تصاعديا لأننا سنستخدم القيمة المنطقية TRUE في حقل range_lookup. نحدد الخلية التي نريد إرجاع النتيجة فيها، وهي الخلية E2 في هذا المثال، ثم نذهب إلى تبويب: صيغ Formulas > بحث وإشارة Lookup & Reference < VLOOKUP في الحقل الأول نحدد القيمة التي نريد البحث عن التقدير الذي يقابلها، وهي قيمة المتوسط للطالب الأول، 82، في هذا المثال (أي الخلية D2). في الحقل الثاني نحدد نطاق الخلايا الذي سيتم البحث عن التقدير المناسب فيه، وهو النطاق H1:I7. في الحقل الثالث نحدد رقم العمود الذي يحتوي على القيمة التي سيتم إرجاعها. وبما أنّ تسلسل عمود "التقدير" هو الثاني في نطاق الخلايا، سندخل الرقم "2". في الحقل الرابع ندخل الرقم 1 (والذي يعني القيمة المنطقية TRUE) أو نتركه فارغًا، وفي الحالتين سيتم إرجاع نفس النتيجة. السبب في أنّنا اخترنا القيمة TRUE هو أننا نبحث عن تطابق تقريبي مع القيم في عمود "الدرجة" وليس تطابق تام. ننقر على OK وسيتم إرجاع التقدير الذي يقابل قيم المتوسط: تفسير عمل الصيغة ستقوم الصيغة بالبحث عن القيمة "82" أو أقرب أقل قيمة إليها، وعند إيجادها، تقوم بإيجاد ما يقابلها في عمود "التقدير"، ومن ثم إرجاع النتيجة في الخلية E2. نستخدم التعبئة التلقائية لنسخ الصيغة إلى بقية خلايا عمود "التقدير": بعد نسخ الصيغة، نلاحظ حدوث خطأ في إيجاد القيم للخلايا من E7 إلى E23، والسبب هو أنّ البرنامج استخدم نطاق الخلايا H1:I7 كمرجع نسبي relative reference. لذلك سنعيد إدراج الصيغة ونستخدم نطاق الخلايا المذكور كمرجع مطلق absolute reference بوضع مؤشر الكتابة فوق اسم الخلية والنقر على مفتاح F4 (أو بكتابة علامة الدولار قبل وبعد حرف العمود يدويا من لوحة المفاتيح) هذه المرة سيتم إيجاد قيم صحيحة في عمود "التقدير" بأكمله عند استخدام التعبئة التلقائية: أو بدلا من استخدام نطاق الخلايا (H1:I7) كمرجع مطلق وتحديده يدويا كلما أردنا استخدام الدالة، نقوم بتسميته باسم مخصص. وبذلك نستطيع استخدام اسم النطاق في الصيغة. نحدد نطاق الخلايا، ندخل الاسم المرغوب في حقل الاسم (قمنا بتسميته بـ "التقدير")، ثم نضغط Enter: في المرة المقبلة، عندما نقوم بإدراج دالة VLOOKUP (أو أيّة دالة أخرى يُستخدم فيها ذلك النطاق)، نقوم بإدخال اسمه بدلًا من تحديده على الورقة: هذه الطريقة هي أفضل وأكثر كفاءة، وتجعلنا نتلافى الأخطاء التي قد تحدث عند استخدام نوع المرجع غير المناسب. HLOOKUP تعمل دالة HLOOKUP (اختصارا لـ Horizontal Lookup) بالضبط كما تعمل دالة VLOOKUP فيما عدا أنّها تقوم بالبحث عن القيم أفقيا وليس عموديا (أي تبحث عن قيمة محددة في صف محدد حسب أعمدة ذلك الصف). البناء العام لصيغة الدالة HLOOKUP(lookup_value; table_array; row_index_num; [range_lookup]) lookup_value: هي القيمة التي تريد البحث عنها. يجب أن تكون هذه القيمة موجودة في الصف الأول لنطاق الخلايا الذي سنحدده في حقل table_array. وهذا المعطى مطلوب في الصيغة. table_array: وهو نطاق الخلايا الذي يحتوي البيانات التي تبحث فيها الدالة. وهذا المعطى مطلوب في الصيغة أيضًا. row_index_num: رقم الصف في نطاق الخلايا table_array الذي يحتوي على القيمة التي سيتم إرجاعها. وجوده مطلوب في الصيغة. range_lookup: هذا المعطى هو عبارة عن قيمة منطقية logical تحدد فيما إذا كنت تريد من دالة HLOOKUP البحث عن تطابق تام (بإدخال القيمة FALSE) أو تطابق تقريبي (بإدخال القيمة TRUE) مع قيمة lookup_value، ووجوده اختياري في الصيغة. ملاحظة: عند استخدام القيمة المنطقية TRUE يجب أن يكون الصف الأول في نطاق الخلايا table_array مرتبا تصاعديا لكي يتم إرجاع قيمة صحيحة. مثال الجدول التالي يحتوي على تواريخ بدء وانتهاء مجموعة من المشاريع. المطلوب هو إيجاد تاريخ انتهاء المشروع رقم 5. بالطبع يمكننا العثور عليه بسهولة في مثل هذا الجدول الصغير، لكن سيصبح الأمر أكثر صعوبة في الجداول الكبير. على كل حال، سنستخدم دالة HLOOKUP للعثور على القيمة المطلوبة. أولا، نحدد الخلية التي نريد إرجاع النتيجة فيها، وهي الخلية B9 في هذا المثال، ثم نذهب إلى تبويب: صيغ Formulas > بحث وإشارة Lookup & Reference < HLOOKUP في مربع الحوار Function Arguments نقوم بتحديد المعطيات: في الحقل الأول، lookup_value، نحدد القيم التي نريد البحث عنها، وهو رقم المشروع "5" في هذا المثال. لذلك سنحدد الخلية B8 التي قمنا بإدخال هذا الرقم فيها مسبقا. في الحقل الثاني، table_array، نحدد نطاق الخلايا الذي سيتم البحث فيه، وهو A1:I13 في هذا المثال. في الحقل الثالث، row_index_num نقوم بإدخال رقم تسلسل الصف الذي يحتوي على النتيجة التي سيتم إرجاعها. وفي هذا المثال هو صف "تاريخ الانتهاء"، تسلسله الثالث (3). في الحقل الرابع، lookup_range نقوم بإدخال الرقم صفر (أي القيمة المنطقية FALSE) لأننا نريد البحث عن قيمة مطابقة تماما للقيمة في حقل lookup_value: ننقر على OK وسيتم إرجاع تاريخ الانتهاء للمشروع رقم 5: تفسير عمل الصيغة ستقوم الصيغة بالبحث في صف "المشروع" عن الرقم 5، وعند العثور عليه ستقوم بإيجاد القيمة المقابلة لهذا الرقم في الصف المحدد في حقل row_index_num، وهو الصف الثالث في مثالنا، ومن ثم إرجاع النتيجة في الخلية B9. يجب أن تأخذ في الاعتبار أنّه إذا كانت قيمة lookup_range تساوي TRUE، ولم تتمكن الدالة من العثور على قيمة lookup_value فستقوم بإرجاع أقرب أقل قيمة من قيمة lookup_value. مثال 2 إذا كنا نريد معرفة تاريخ البداية للمشروع رقم "9" (والذي هو في الحقيقة غير موجود في الجدول) ستكون الصيغة كالتالي: وستكون النتيجة كالتالي: تفسير عمل الصيغة قامت الصيغة بالبحث عن الرقم "9" في صف "المشروع"، وقد تعذّر عليها إيجاده، لذلك قامت بإرجاع "تاريخ البدء" للمشروع رقم "8" وهو أقرب أقل قيمة من الرقم "9". وهذا بسبب أننا قمنا بإدخال القيمة المنطقية TRUE (أي البحث عن تطابق تقريبي). أما إذا قمنا بتحديد القيمة المنطقية FALSE، فستكون النتيجة خطأ #N/A، لأنّ الدالة في هذه الحالة ستبحث عن تطابق تام:
  10. python 101

    المُزخرفات من أعظم مميزات لغة بايثون، إذ تساعدك على بناء برنامجك باحترافية أكثر موفرة طريقة بسيطة لإضافة خاصيات جديدة للدالة. وهي ببساطة دوال تستطيع أن تعدل على دوال أخرى. تذكير ببعض المفاهيم الأساسية إذا لم تكن تعرف شيئا عن الدوال في لغة بايثون فيجب عليك العودة للدرس السابق الدوال في بايثون قبل أن تكمل قراءة هذا الدرس. تُعتبر الدوال في لغة بايثون كائنات من نوع الفئة الأولى أو First class objects. ما يعني أنّنا نستطيع القيام بالعديد من العمليات، وهي كالتالي: يُمكنك تعريف دالة داخل دالة أخرى يُمكنك أن تستدعي دالة داخل أخرى يُمكنك أن تقوم بتمرير دالة كمُعامل لدالة أخرى يُمكنك أن تُسند دالة لمُتغير يُمكنك إرجاع دالة داخل دالة أخرى بما أنّ المُزخرفات مُجرّد دوال فعلينا أن نبدأ من الأساس، لاحظ الدالة التالية: def say_hello(): print 'Hello!' عند استدعاء الدالة ستُطبع القيمة Hello على الشاشة، هذا ليس بالأمر المُعقد، الآن ماذا لو أردنا أن نعدل الدالة في جزء آخر من البرنامج لكي تطبع أشياء أخرى وتؤدي أغراضا أخرى قبل استدعاء الدالة أو بعد ذلك؟ يُمكن أن نعدّل الدالة مُباشرة، لكن هذا الأمر سيغير من طريقة سير البرنامج، إذ نريد أن نعدل الدالة في منطقة واحدة فقط من البرنامج وليس في كامل البرنامج، هذه المسألة تُحل بالمُزخرفات، وكما يدل اسمها فهي دوال تُزيّن وتُزخرف الدالة الأصلية، أي تُضيف عليها مهاما أخرى. سننشئ لهذه الدالة الآن مُزخرفا Decorator يقوم بطباعة Before قبل تنفيذ الدالة و After بعد تنفيذ الدالة، وذلك دون تعديل الدالة مُباشرة. انظر المثال التالي: def decorator(function): def function_decorator(): print 'Before' function() print 'After' return function_decorator الشيفرة أعلاه عبارة عن دالة تقبل دالة أخرى (الدالة التي نرغب بزَخرَفَتِها أو تزيينها) كمُعامل وبعدها نقوم بإنشاء دالة داخل هذه الدالة لطباعة القيمة Before ثم استدعاء الدالة الأصلية (المُعامل) بعدها طباعة After وأخيرا إرجاع الدالة الجديدة (وهي نُسخة مزخرفة من الدالة الأصلية). بعدها يُمكننا أن نستخدم هذا المُزخرف لزخرفة أي دالة مهما كانت، انظر المثال التالي: # -*- coding: utf-8 -*- def decorator(function): # إنشاء الدالة المسؤولة عن الزخرفة def function_decorator(): # إنشاء الدالة التي ستكون نسخة مزخرفة من الدالة المُمرّرة في كمُعامل print 'Before' # طباعة جملة قبل تنفيذ الدالة function() # استدعاء الدالة print 'After' return function_decorator # إرجاع الدالة مُزَخْرَفَةً def say_hello(): # إنشاء دالة عادية print 'Hello!' say_hello = decorator(say_hello) # زخرفة الدالة say_hello() # استدعاء النُسخة المُزخرفة من الدالة توفر لنا لغة بايثون طريقة أكثر مرونة لزخرفة الدوال، وهي بوضع اسم المُزخرف مسبوقا بالحرف @ قبل تعريف الدالة. أي أنّ السّطر التالي: def say_hello(): print 'Hello!' say_hello = decorator(say_hello) # زخرفة الدالة يُمكن أن يكون كالتالي: @decorator def say_hello(): # إنشاء دالة عادية print 'Hello!' وبالتالي سنتمكن من زخرفة أي دالة نرغب بزخرفتها كالتالي: @decorator def say_hello(): print 'Hello!' @decorator def say_hi(): print 'Hi!' @decorator def say_name(): print 'Abdelhadi!' say_hello() say_hi() say_name() عند تنفيذ الشيفرة أعلاه ستكون المخرجات كالتالي: Before Hello! After Before Hi! After Before Abdelhadi! After مُلاحظة: إذا كانت للدالة معاملات فما عليك إلا استخدام args* التي سبق وتحدثنا عنها في الدرس السابق. # -*- coding: utf-8 -*- def decorator(function): # إنشاء الدالة المسؤولة عن الزخرفة def function_decorator(*args): # إنشاء الدالة التي ستكون نسخة مزخرفة من الدالة المُمرّرة كمُعامل print 'Before' # طباعة جملة قبل تنفيذ الدالة function(*args) # استدعاء الدالة print 'After' return function_decorator # إرجاع الدالة مُزَخْرَفَةً لاحظ الدالتين function_decorator و function. أمثلة على المزخرفات في لغة بايثون إذا فهمت مبدأ المزخرفات فستستطيع أن تتعامل مع الدوال بمرونة عالية، وإليك بعض الأمثلة لاستخدام المُزخرفات لتأدية بعض المهام البسيطة: حساب مدة تنفيذ دالة إذا فهمت جيدا مبدأ المُزخرفات فستلاحظ بأنّك تستطيع تنفيذ مهام قبل تنفيذ الدالة ومهام بعد تنفيذها، ومما سبق نستنتج بأنّنا نستطيع أن نقوم بحفظ الوقت الحالي في مُتغير ثم تنفيذ الدالة وبعدها نقوم بحساب الفرق بين الوقت السابق والوقت الحالي، ما سيُرجع المُدة المُستغرقة لتنفيذ الدالة. البرنامج التالي مثال على مُزخرف لحساب مُدة دالة تطبع الجملة !Hello World مليون مرّة. # -*- coding: utf-8 -*- import time # جلب مكتبة الوقت لاستعمال دوال الوقت def function_time(function): def function_decorator(*args): start_time = time.time() # الحصول على وقت البداية function(*args) end_time = time.time() # الحصول على الوقت بعد نهاية التنفيذ # طباعة اسم الدالة والفرق بين وقت البداية ووقت النهاية print '%s function took %0.3f s' % (function.func_name, (end_time - start_time)) return function_decorator # إرجاع الدالة مُزَخْرَفَةً # زخرفة الدالة المسؤولة عن الطباعة مليون مرة @function_time def print_million_times(): for i in range(0, 1000000): print 'Hello World! 1,000,000 times!' print_million_times() البرنامج أعلاه سيطبع الجملة مليون مرة ثم يعرض الوقت المُستغرق لإنجاز العملية. الجملة الأخيرة ستكون شيئا كالتّالي: print_million_times function took 69.584 s ملاحظات: نستعمل التابع func_name للحصول على اسم الدالة المُمررة كمعامل، ويكون على شكل سلسلة نصية. نستعمل الجملة time.time للحصول على الوقت بالثواني، عدد الثواني الذي تنتجه الجملة هو عدد الثواني الذي مرّ منذ سنة 1970. يُمكنك استعمال هذا المُزخرف مع أي دالة تريد فقط اكتب اسم المُزخرف مسبوقا بالحرف @ ثم عرف الدالة بعده، وستحصل على الوقت المُستغرق لتنفيذ الدالة. حساب عدد مرات استدعاء دالة يُمكننا أن نستخدم المُزخرفات للحصول على عدد المرات التي استدعيت فيها دالة ما في برنامج مُعيّن، بحيث يحمل متغير قيمة العدد صفر، وفي كل مرة تستدعى فيها الدالة، فإن المُتغير يحمل القيمة مع زيادة بالعدد واحد، انظر المثال التالي. # -*- coding: utf-8 -*- # متغير العد n = 0 # المُزخرف def call_times(function): def decorated(): function() # استدعاء الدالة global n # جعل مُتغير العدّ عالميا n += 1 # زيادة قيمة المُتغير print 'Function was called', n, 'times' # طباعة قيمة المُتغير return decorated @call_times # زخرفة الدالة def func(): # إنشاء الدالة print 'Hello!' # استدعاء الدالة func() func() func() func() مُخرجات البرنامج أعلاه ستكون كالتالي: Hello! Function was called 1 times Hello! Function was called 2 times Hello! Function was called 3 times Hello! Function was called 4 times يُمكنك إصلاح الجمل من الناحية اللغوية بإضافة بعض العبارات الشرطية للبرنامج. إنشاء مزخرف لتنفيذ دالة عند تحقق شرط معين فقط يُمكنك أن تستعمل دالة تسجيل الدخول التي قُمنا بإنشائها كمُزخرف للدوال التي تحتاج لأن يكون المُستخدم مُسجلا دخوله. مثلا لنقل بأنّنا نريد أن نعرض على المُستخدم عدة خيارات بعضها يحتاج إلى تسجيل دخول المُستخدم وبعضها لا. الخيارات كالتّالي: تسجيل مُستخدم جديد (تسجيل الدخول غير مطلوب) طباعة جملة عشر مرات ( تسجيل الدخول غير مطلوب) الحصول على الوقت الحالي ( تسجيل الدخول غير مطلوب) طباعة اسم المُستخدم (تسجيل الدخول مطلوب) رؤية معلومات الحساب (تسجيل الدخول مطلوب) تعديل كلمة المرور (تسجيل الدخول مطلوب) مبدأ عمل البرنامج سيكون كالتالي: إنشاء الدوال المسؤولة عن الخيارات عرض الخيارات على المُستخدم زخرفة الدوال التي تطلب تسجيل المُستخدم بمُزخرف تسجيل الدخول المُزخرف سيتحقق من أنّ المُستخدم قد سجل دخوله، إذا كان الأمر كذلك، تنفّذ الدالة وإذا لم يتحقق الشرط فلا تنفذ. لنقل بأنّ اسم مُزخرف التحقق من تسجيل الدخول هو is_user_logged_in، ستكون الدوال التي تطلب تسجيل الدخول مُزَخْرَفَةً كالتالي: @if_user_logged_in def account_info(): print 'Username:', username, 'Password:', password تمارين تمرين 1 أنشئ دالة للجمع بين عددين، وبعدها أنشئ مُزخرفا يقوم بمُضاعفة النتيجة. تمرين 2 أنشئ دالة للحصول على قيم من المُستخدم وقم بزخرفة لطباعة جملة ترحيب قبل استدعاء الدالة وجملة توديع بعد استدعاءها. تمرين 3 أكمل البرنامج الخاص بالمثال الثالث (إنشاء مُزخرف لتنفيذ دالة عند تحقق شرط مُعين فقط). تفاصيل التمرين موجودة بالمثال.
  11. php 101

    عندما نكتب برنامجًا طويلًا جدًا، فإن الشيفرة ستوزَّع في عددٍ من الملفات والأصناف (classes) والدوال (functions)؛ الدوال هي مجموعة من التعليمات التي تنجز مُهمِّة معيّنة وهدفها ألا تكرر الشيفرات التي تكتبها؛ فمثلًا في نظام للاستيثاق، يكون هنالك دوال لتسجيل الدخول (login) والتسجيل (register) وتسجيل الخروج (logout). أبسط أشكال الدوال إن الشكل العام لأبسط دالة هو: <?php function function_name() { // الشيفرة } ?> وكما في المتغيرات، تستطيع إسناد أي اسم إلى الدالة (أعطينا الدالة في المثال السابق الاسم function_name). تُكتَب الشيفرة التي ستنفذها الدالة عندما يتم استدعاؤها بين أقواس معقوفة ({})؛ نستطيع استدعاء الدالة عبر كتابة اسمها ويليه أقواس عادية () كما في المثال الآتي: <?php // يمكنك أن تستدعي الدالة هنا قبل تعريفها // تعريف دالة ذات الاسم say_hello function say_hello() { // كل ما تفعله هذه الدالة هو طباعة hello echo "hello"; } // استدعاء الدالة say_hello(); ?> الدوال ذات الوسائط يمكننا تمرير المعلومات الإضافية (مثل اسم المستخدم وكلمة المرور) إلى الدوال باستخدام الوسائط (arguments)، وعلينا تعريف المعاملات (parameters). ملاحظة: الوسائط هي البيانات التي نمررها إلى الدالة عندما نستدعيها، أما المعاملات فهي المتغيرات التي نُعرِّفها عندما نكتب الشيفرة الخاصة بالدالة. يمكننا أن نعتبر أن المعاملات هي حاويات والوسائط هي البيانات التي نضعها في تلك الحاويات. <?php // دالة تسجيل الدخول ذات وسيطين function login($user, $pass) { // تطبع هذه الدالة اسم المستخدم وكلمة المرور echo "hello, username is $user and password is $pass"; } // استدعاء الدالة login("user1","UsEr!p@$$W0rD"); // استدعاء الدالة مرةً أخرى login("user2","simplepassword"); ?> المعاملات ذوات القيم الافتراضية يمكننا أن نعطي قيمًا افتراضية للمعاملات لكي يمكن تجاوز تحديد قيمتها عند استدعاء الدالة. <?php // دالة تسجيل الدخول ذات ثلاثة وسائط function login($user, $pass, $active = "not active") { // تعرِض هذه الدالة اسم المستخدم وكلمة مروره وحالته echo "hello, username is $user and password is $pass and user is $active"; } // استدعاء الدالة login('user1','UsEr!p@$$W0rD'); // استدعاء الدالة مرةً أخرى login('user2','simplepassword', 'active'); ?> ملاحظة: إن أردت ألّا تُحدِّد قيمةً لوسيطٍ ما عند استدعاء الدالة، فيجب أن يكون المعامل الموافق لذاك الوسيط في آخر القائمة كما في المثال السابق. ويملك المعامل افتراضيًا القيمة "null". الدوال ذات المعاملات متغيرة العدد يمكن أن تملك الدوال عددًا متغيرًا من المعاملات؛ وفي الواقع، تستطيع تمرير إي عدد من الوسائط إلى دالة؛ استعمل الدوال المُضمَّنة في PHP الآتية للوصول إلى تلك الوسائط: الدالة func_get_args()‎: تُعيد مصفوفة بجميع الوسائط المُمرَّرة الدالة func_num_args()‎: تُعيد العدد الإجمالي للوسائط المُمرَّرة. الدالة func_get_arg(argument_number)‎: تُعيد المتغير ذو الرقم argument_number سنظهِر -في المثال الآتي- مجموع الأرقام المُمرَّرة إلى الدالة كوسائط بالإضافة إلى عرضها. <?php function sum() { // سنستعمل func_get_args() للحصول على كل المعاملات على شكل مصفوفة $ary = func_get_args(); print_r($ary); echo "<br>"; $sum = 0; // سنستعمل func_num_args للحصول على العدد الكلي للمعاملات for($i = 0; $i < func_num_args(); $i++) { // سنستعمل func_get_arg(index) للحصول على قيمة معامل معيّن echo func_get_arg($i).'<br>'; $sum+= func_get_arg($i); } echo "sum is $sum <br><br>"; } sum(1,2,3,4); sum(23,2343,54,2,1,6); ?> ناتج تنفيذ السكربت السابق هو: Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) 1 2 3 4 sum is 10 Array ( [0] => 23 [1] => 2343 [2] => 54 [3] => 2 [4] => 1 [5] => 6 ) 23 2343 54 2 1 6 sum is 2429 إعادة القيم من الدوال لاحظ أننا في المثال السابق طبعنا السلسلة النصية مباشرةً، لكن ماذا لو أردنا أن نجعل الدالة تُعيد قيمةً ما؟ نستعمل العبارة البرمجية return لإعادة قيمة من الدالة، وتُسبِّب هذه العبارة بإنهاء تنفيذ الدالة مباشرةً وإعادة القيمة إلى مكان استدعاء الدالة، لنرى مثالًا عن دالة تُعيد مربَّع العدد المُمرَّر إليها: <?php function square ($num) { return $num * $num; } // الناتج هو 16 echo square (4); ?> لاحظ أنك لا تستطيع إعادة أكثر من قيمة من الدالة، لكن يمكنك إعادة مصفوفة التي تؤدي نفس الدور تقريبًا. <?php function powers ($num) { return array ($num, $num * $num, $num * $num * $num); } // الناتج هو: Array ( [0] => 4 [1] => 16 [2] => 64 ) print_r(powers (4)); ?> مجالات تعريف الدوال تستطيع أن تستدعي الدوال المُعرَّفة في الأمثلة السابقة قبل مكان تعريفها، لأن مجالها (scope) هو المجال العام، يجدر بالذكر أنَّك تستطيع تعريف الدوال داخل جملة شرطية (if) لكن لا يمكنك استدعاؤها إن لم يتحقق الشرط كما في المثال الآتي: <?php $str = 'create the function'; global_function(); // لا يمكننا استدعاء الدالة not_global هاهنا، لأن المفسر لا يعتبرها موجودةً إن لم تتحقق الجملة الشرطية الآتية if ($str == 'create the function') { function not_global() { echo 'I don\'t exist until program execution reaches me'; } } // نستطيع الآن استدعاء الدالة not_global بعد اختبار أن السلسلة $str مساوية للقيمة اعلاه، لتجنب إظهار خطأ if ($str == 'create the function') not_global(); function global_function() { echo 'I exist immediately upon program start'; } ?> الأمر سيان لآلية تعريف دالة داخل دالة أخرى: <?php function global_function() { function not_global() { echo 'I don\'t exist until global_function() is called'; } } // لا يمكننا استدعاء not_global هنا، إذ علينا استدعاء global_function أولًا global_function(); // نستطيع الآن استدعاء الدالة not_global، لأن استدعاء global_function قد جعلها متاحةً للمفسر not_global(); ?> المتغيرات في الدوال مجال المتغيرات (variable scope) هو "المجال" الذي يبقى فيه المتغير مُعرَّفًا، أي بكلامٍ آخر، المتغيرات المُعرَّفة داخل الدوال لا يمكن الوصول إليها من خارج تلك الدوال؛ أما المتغيرات المُعرَّفة في المجال العام (global scope) يمكن الوصول إليها من أي جزء من البرنامج في المجال العام؛ ربما أربكك الشرح السابق لكن انظر إلى هذا المثال للتوضيح: <?php // المتغير $a في المجال العام $a = 1; function test() { echo $a; // لا يمكن الوصول إلى المتغير $a لأنه في المجال العام } // لن يظهر أي شيء ﻷن المتغير $a ليس ضمن مجال الدالة test(); // سيظهر الرقم 1، لأن المجال هو العام echo $a; ?> لن تظهر مخرجات عند استدعاء الدالة test()‎ لأن الدالة echo داخلها تُشير إلى نسخة محلية من المتغير ‎$a التي لم تُسنَد لها قيمة في ذاك المجال. يمكن الوصول إلى المتغيرات في المجال العام من داخل الدوال باستخدام الكلمة المحجوزة global كما يلي: <?php $a = 1; $b = 2; function sum (){ // أصبح بإمكاننا الوصول إلى المتغيرين في مجال الدالة الخاص، وتعديل قيمتهما مباشرةً global $a, $b; $b = $a + $b; } sum(); echo $b; ?> نوعٌ أخيرٌ هو المتغيرات الثابتة (static variables) التي يُسمَح بوجودها في مجال الدوال الخاص فقط، لكنها لا تفقد قيمتها عند انتهاء تنفيذ الدالة، انظر إلى المثال الآتي لتوضيح الأمور: <?php function test() { $a = 0; echo $a; $a++; } ?> الدالة السابقة عديمة الفائدة لأنها في كل مرة تُستدعى فيها ستضبط قيمة المتغير ‎$a إلى 0، ثم ستُظهِر قيمة ذاك المتغير (التي هي صفر)، وأخيرًا لن نستفيد من زيادة قيمة المتغير (‎$a++‎) لانتهاء تنفيذ الدالة ولن يعود المتغير ‎$a موجودًا. أما لو عرَّفنا المتغير ‎$a على أنه ثابت، فلن يفقد قيمته بعد انتهاء تنفيذ الدالة: <?php function test() { static $a = 0; echo $a; $a++; } ?> ستتم تهيئة المتغير ‎$a في أول مرة تُستدعى فيها الدالة، وستُطبَع قيمة المتغير وستزداد قيمته في كل مرة تستدعى فيها الدالة مرةً أخرى. <?php function test() { static $a = 0; echo $a; $a++; } //الناتج 0 test(); //الناتج 1 test(); //الناتج 2 test(); ?> ملاحظة: يجب إسناد قيم بسيطة إلى المتغيرات الثابتة عند تعريفها، إذ لا يجوز استعمال التعابير الرياضية أو إسناد القيم المُعادة من الدوال إليها. المعاملات المرجعية رأينا كيف أنَّ جميع الدوال السابقة تعيد قيمة ما بناءً على العمليات التي تُجرى فيها، لكنها لا تستطيع تعديل قيم الوسائط المُمرَّرة إليها، لكن "التمرير بالمرجعية" (pass by reference) يسمح للدوال بتعديل قيم الوسائط مباشرةً، لنأخذ مثالًا بسيطًا يوضِّح هذا الأمر: <?php function test(&$var) { $var++; // لاحظ عدم استعمال عبارة return هنا } $a = 5; test($a); echo $a; // الناتج هو 6 ?> الاختلاف الوحيد الذي يجعل الوسائط تُمرَّر بمرجعيتها هو وضع محرف «&» قبل اسم الوسيط عند تعريف الدالة. الدوال المجهولة الدوال المجهولة (anonymous functions) التي تُعرَف أيضًا بالمصطلح "closures" تسمح بإنشاء دالة ليس لها اسم محدد، وإنما تُسند مباشرةً إلى متغير مَثَلُها كَمَثَلِ أيّةِ عملية إسنادٍ أخرى، وتنتهي عملية الإسناد أيضًا بفاصلة منقوطة؛ هذا مثالٌ عنها: <?php $square = function ($num) { echo $num * $num; }; $square(2); // الناتج 4 $square(15); // الناتج 225 ?> نستطيع أن نُمرِّر إلى الدوال المجهولة أي متغير موجود في مجال المتغيرات الأعلى منها وذلك باستخدام الكلمة المحجوزة use، تأمّل في المثال الآتي وفي تعليقاته: <?php $message = 'hello'; // لم نستعمل الكلمة المفتاحية use هنا $example = function () { echo $message; }; $example(); // لن تَظهَر أيّة قيمة (أو بالتحديد، سيظهر خطأ Notice ﻷن المتغير غير مُعرَّف) // تمرير المتغير $message $example = function () use ($message) { echo $message; }; $example(); // الناتج: hello // القيمة المُمرّرة تؤخذ قبل تعريف الدالة، وليس قبل استدعائها $message = 'world'; $example(); // الناتج: hello // إعادة قيمة المتغير إلى قيمته الأصلية $message = 'hello'; // الوراثة بالمرجعية (inherit by-reference) $example = function () use (&$message) { echo $message; }; $example(); // الناتج: hello // إذا تغيرت قيمة المتغير الآن، فستتأثر الدالة المجهولة بها $message = 'world'; $example(); // الناتج: world // استعمال الوسائط العادية $example = function ($arg) use ($message) { echo $arg . ' ' . $message; }; $example("hello"); // الناتج: hello world ?> تمرين اكتب دالةً تقبل وسيطين أولهما هو طول المستطيل والآخر هو عرض المستطيل، وستعيد هذه الدالة أربع قيم تُمثِّل إحداثيات نقاط التقاء أضلاعه على فرض أنَّ مركزه يقع على مبدأ الإحداثيات. المصادر مقال Functions in php لصاحبه Harish Kumar. مقالتي Functions و Closures لصاحبهما Dayle Rees. صفحات Functions و Anonymous functions و User-defined functions في دليل php وغيرها.
  12. سنتعرّف في هذا الدّرس على كيفية التّعامل مع الأرقام في روبي. سنقوم في البداية بالتعامل مع العمليّات الحسابيّة من خلال سطر أوامر روبي التفاعليّ. ثمّ سنتعرّف بعد ذلك على الأعداد الصحيحة Integers والدوال الخاصّة بها. كما سنتعرف أيضًا على كيفية توليد أرقام عشوائيّة في روبي. الأرقام لنلق الآن نظرة على استخدام الأرقام في سطر أوامر روبي التفاعليّ. افتح الطرفيّة وابدأ جلسة IRB جديدة عن طريق كتابة أمر irb. يمكننا كتابة عمليّة جمع كالتالي: 3 + 5 علامة الجمع في الأمر السّابق هي عبارة عن دالّة خاصّة بالرقم 3 (الذي يعدّ كائنًا، كما ذكرنا سابقًا أن روبي تتعامل مع أي شيء على أنّه كائن له دوالّ خاصّة به). قد تتساءل كيف لعلامة + أن تكون دالّة وقد تعرّفنا أن استدعاء الدوال يتم عن طريق إضافة نقطة ثم اسم الدّالّة بعد الكائن. دعني أخبرك أنّه يمكن بالفعل تنفيذ الدّالّة + بهذه الطريقة. ولأنّنا نريد إضافة 5 إلى 3 فإنّنا نريد إضافة ما يسمّى بالمعطى Argument والذي يوضع بين قوسين بعد اسم الدّالّة. لذلك فيمكن إعادة كتابة الأمر السّابق هكذا: 3.+(5) إذا كتبت الأمرين ستحصل على نفس النّتائج. إذًا فرقم 3 هو الكائن الذي يستدعي الدّالّة، علامة الجمع هي اسم الدّالّة وبين القوسين نجد المعطى هو رقم 5. ولأنّه عند كتابة عمليّة الجمع بهذه الطريقة يبدو الأمر صعبًا بعض الشيء، فهذا الاستدعاء لا يبدو كعمليّة الجمع المألوفة لنا. لذلك فإنّ روبي تسمح لنا باستخدام الدّالّة بالصورة الأولى والتي تبدو أسهل في القراءة والاستخدام لإتمام عمليّات الجمع. يسمّى هذا بالتجميل اللّغوي Syntactic Sugar. لذلك فإن الطريقة الأولى لإتمام عمليّة الجمع هي الأكثر شيوعًا عن التنويت النقطي Dot Notation. لدى روبي الكثير من العمليّات الحسابيّة الأخرى. مثل الطرح: 10 – 4 الضرب: 4 * 8 القسمة: 9 / 2 إذا كنت تنفّذ الأوامر السّابقة في سطر أوامر روبي التفاعليّ ستلاحظ أنّ ناتج عمليّة قسمة 9 على 2 هو 4، وهذا ليس صحيحًا فحاصل قسمة 9 على 2 هو 4.5 وليس 4، أليس كذلك؟ حدث ذلك لأنّ 9 و2 هي أرقام صحيحة ممّا يعني أنّ الناتج سيكون أيضًا الجزء الصحيح فقط من خارج القسمة وهو في هذه الحالة 4 بدلاً من 4.5. للحصول على الناتج الصحيح لهذه العمليّة نحتاج إلى استخدام نوع آخر من كائنات الأرقام يسمّى بالعدد العشري Float. لاستخدام عدد عشري بدلاً من عدد صحيح كل ما علينا فعله هو على سبيل المثال كتابة 9.0 بدلاً من 9. جرّب إعادة كتابة عمليّة القسمة السّابقة باستخدام 9.0. ستجد أنّ روبي قد أعادت النّاتج 4.5. دالتا even وodd تستخدم روبي دالتين لمعرفة ما إذا كان العدد زوجيًّا أم فرديًّا. على سبيل المثال اكتب الأمر التّالي ولاحظ النّتيجة: 62.even? بعد الضغط على Enter ستطبع روبي على الشّاشة true ردًّا على سؤالنا لها هل العدد 62 عددًا زوجيًّا؟. يمكننا أيضًا استخدام دالّة odd للتحقّق ممّا إذا كان العدد 62 زوجيًّا أم فرديًّا هكذا: 62.odd? تحدّثنا في الدّرس السّابق عن دوال Bang وكيف أنّها تنتهي بعلامة تعجّب. دالّتي even و odd هما مثالين للدوال الشرطيّة وهي الدوال التي ترجع true أو false وغالبًا ستجد علامة استفهام بنهاية تلك الدوال والتي تجعل من السّهل تمييز هذا النّوع. دالة GCD يمكن لروبي تنفيذ بعض العمليّات الحسابيّة اللّطيفة أيضًا. على سبيل المثال يمكن إيجاد القاسم المشترك الأكبر لعددين (وهو أكبر عدد يقسم في نفس الوقت العددين معًا بدون أيّ باقي قسمة) باستخدام دالّة gcd. إذًا لو أردت معرفة القاسم المشترك الأكبر لكلٍّ من 12 و20 فيمكن كتابة هذا كالتّالي: 12.gcd(20) وستكون النتيجة 4 دالة LCM دالّة lcm مشابهة نوعًا ما لدالّة gcd وتقوم بإيجاد المضاعف المشترك الأصغر لعددين (وهو أصغر عدد موجب صحيح مضاعف لكلا هذين العددين، أي أنّه يمكن قسمة هذا المضاعف المشترك الأصغر على العددين بدون باقي قسمة). إذا أردت معرفة المضاعف المشترك الأصغر لكل من 15 و20 يمكن كتابة هذا كالتّالي: 15.lcm(20) وستكون النتيجة 60 دالة to_s آخر دالّة خاصّة بالأعداد الصحيحة التي سنتطرّق إليها هي دالّة to_s والتي هي اختصار لـ to string. يمكنك من اسمها تخمين وظيفتها، تقوم الدّالّة بتحويل عدد صحيح إلى سلسلة حرفيّة تحتوي على هذا الرقم. على سبيل المثال، الشيفرة البرمجيّة التالية تقوم بتحويل العدد الصحيح 7 إلى سلسلة "7": 7.to_s بعد الضغط على Enter سيتم إرجاع القيمة هكذا "7". نعرف أنّ القيمة نوعها سلسلة من علامات الاقتباس المحيطة بها. الآن يمكننا التّعامل مع هذا الرقم على أنّه سلسلة وتنفيذ دوال السّلاسل عليه. دالة to_i دالّة to_i مشابهة لدالّة to_s ولكنّها خاصّة بالسّلاسل، تقوم الدّالّة بتحويل السلسلة إلى عدد صحيح. لذلك فيمكننا كتابة "42" وتحويلها إلى عدد صحيح هكذا: "42".to_i سنلاحظ بعد تنفيذ الأمر إرجاع قيمة صحيحة عبارة عن 42 وستختفي علامات الاقتباس المحيطة بالعدد. بذلك يمكننا استخدام الدوال الخاصّة بالأعداد الصحيحة على 42، مثل الجمع والطّرح. عليك توخّي الحذر عند التّعامل مع هذه الدّالّة، حيث أنّه في حالة عدم احتواء السلسلة على أيّة أرقام فسوف تقوم بإرجاع قيمة 0. على سبيل المثال اكتب الأمر التّالي ولاحظ الناتج: "Hello World".to_i أمّا في حالة تنفيذ الدّالّة على سلسلة تبدأ بقيمة عدديّة فستقوم الدّالّة بتحويل وإرجاع الرقم الموجود في أوّل السلسلة فقط. مثال على ذلك: "2016 Jan".to_i دالة Rand يُعدّ توليد أرقام عشوائيّة أحد الأمور المفيدة في البرمجة وله استخدامات عديدة، يمكن فعل ذلك في ruby بسهولة عن طريق استخدام دالّة rand. باستخدام الدّالّة يمكننا توليد عدد عشري بين 0 و 1.0. كلّ ما عليك فعله هو كتابة rand في سطر أوامر روبي التفاعليّ والضّغط على Enter، جرّب كتابة الأمر أكثر من مرّة ولاحظ كيف تختلف القيمة في كلّ مرّة ولكنّها لا تزيد عن 1.0 ولا تقلّ عن 0. ولكن ماذا إذا أردت الحصول على أرقام عشوائيّة صحيحة؟ إذا أضفت عددًا صحيحًا للدّالّة كمُعطى فستقوم الدّالّة بتوليد عددًا عشوائيًّا صحيحًا بين 0 والعدد المعطى ولكن العدد المعطى لن يكون ضمن تلك الأعداد العشوائيّة. فمثلاً إذا أعطيت الدّالّة رقم 6 ستقوم بتوليد رقمًا عشوائيًّا بين 0 و 5: rand(6) ماذا لو أردت البدء من 1 بدلاً من 0؟ توفّر روبي طريقة لطيفة لفعل ذلك. كلّ ما علينا فعله هو إدخال مجال range معيّن من القيم كمُعطى للدّالّة فنكتبها هكذا: rand(1..6) الأمر السّابق يخبر روبي بأن تختار رقمًا عشوائيًّا بين 1 و 6، متضمّنة 1 و 6 أيضًا ضمن الأرقام العشوائيّة. يذكّرنا هذا بلعبة إلقاء النّرد، أليس كذلك؟ خاتمة تعرّفنا في هذا الدّرس على بعض المفاهيم المهمّة في روبي مثل الأرقام والدوال الخاصّة بها وكيفيّة تحويل رقم إلى سلسلة والعكس. هدف هذا الدّرس هو إعطاؤك لمحة سريعة عن العمليات التي يُمكن تنفيذها على الأرقام ومبدأ عمل ذلك. بطبيعة الحال لم نستعرض سوى عدد محدود من الدّوال. بإمكانك الاطّلاع على باقي الدّوال عبر زيارة التّوثيق الرّسمي للغة وخاصة صفحة الأرقام الصّحيحة.
  13. تعرّفنا في الدّرس السّابق على لغة روبي ووميزاتها. في هذا الدّرس سوف نستعرض بعض أنواع البيانات في Ruby، وسنتعرّف باستفاضة على نوع السلاسل. كما سنتعرّف على أحد أهمّ سمات أيّ لغة برمجة، ألا وهي المتغيّرات. سنستخدم في الجزء الأول من الدّرس سطر أوامر روبي التفاعليّ. افتح الطرفيّة وابدأ جلسة irb عن طريق كتابة أمر irb والضغط على زر Enter. القيم والأنواع القيمة هي أبسط شيء يتعامل معه البرنامج مثل حرف أو رقم. تعرّفنا في الدّرس السّابق على بعض تلك القيم. تختلف القيمة 2 عن القيمة "Hello World"، حيث أن الأولى هي عدد صحيح Integer أمّا الثّانية فهي من نوع سلسلة String، جاءت التسمية من كونها سلسلة من الأحرف. يمكنك التعرّف بسهولة على السلاسل من خلال علامات الاقتباس المحيطة بالقيمة. هناك نوع آخر يسمّى Float وهو أيّ رقم يحتوي على علامة عشريّة، مثلاً: 2.5، 13.6، 4.0. ملحوظة: قد تعتقد أن "12" و"1.5" هي أرقام وتتعامل معها في برنامجك على ذلك فتنفّذ عليها عمليّات حسابيّة وتكتشف بعد ذلك أنّ مفسّر روبي يظهر لك علّة برمجية Bug. سبب ذلك أنّها ربّما تكون أرقامًا بالنسبة لك ولكن المفسّر يعتبرها سلاسل نصيّة حيث أنّها محاطة بعلامات الاقتباس والمفسّر مُبَرْمَج على تصنيف أيّ شيء بين علامات اقتباس على أنّه سلسلة. تريد التأكد من ذلك بنفسك؟ جرّب جمع "12" + "1.5". أو بطريقة أخرى يمكنك استخدام الدّالة المدمجة is_a لسؤال روبي هل هذه القيمة نوعها Integer مثلاً وستردّ عليك روبي true أو false. فمثلاً إذا أردت التأكّد من نوع قيمة معيّنة مثل 12 اكتب الأمر التالي: 12.is_a?(Integer) الآن للعودة إلى ما إذا كان كل من "12" و"1.5” أرقامًا أم سلاسل، جرّب الأوامر التالية (تأكّد من كتابة أوّل حرف بشكل كبير Capital): "12".is_a?(Integer) "1.5".is_a?(Float) أحيانًا عند كتابة أعداد كبيرة قد تجد نفسك محتاجًا إلى إرفاق فواصل لجعل العدد قابلاً للقراءة أكثر، مثلاً 1,000,000. لو فعلت ذلك في روبي ستحصل على خطأ. ولكن يمكنك فعل ذلك مع الأمر puts. مثلاً يمكن كتابة: puts 1,000,000 ماذا كانت النتيجة؟ لم تتوقعها أليس كذلك؟ قامت روبي قامت بطباعة: 1 0 0 رقم 1 و 0 و 0 في أسطر مختلفة. حدث ذلك لأنّ روبي قد فسّرت هذا العدد على أنّه ثلاثة أرقام مستقلّة ومفصول بينها بفواصل. في روبي يمكن استخدام الأمر puts لطباعة أكثر من قيمة في أكثر من سطر عن طريق الفصل بين تلك القيم بفاصلة. فمثلاً لو أردت طباعة "Hello" في سطر وبعدها "World" في سطر باستخدام أمر روبي واحد يمكن استخدام الأمر التالي: puts "Hello", "World" Hello World السلاسل السلاسل في روبي هي مجموعات من الأحرف. يمكن إنشاء سلسلة نصيّة عن طريق كتابة أحرف ونصوص داخل علامتي اقتباس مزدوجة. مثلاً لكتابة سلسلة تحتوي على نصّ Hello Ruby اكتب الأمر التّالي: "Hello Ruby" يمكن استخدام علامة الاقتباس المفردة أيضًا لإنشاء سلسلة في روبي، لذلك فيمكن إنشاء السلسلة السّابقة كالتّالي: 'Hello Ruby' إذا أردت استخدام أحد نوعي علامات الاقتباس في داخل نصّك فعليك استخدام النّوع الآخر لإنشاء السلسلة فمثلا لو أردت إنشاء سلسلة نصيّة بها I'm learning Ruby، واستخدمت علامة الاقتباس المفردة لإنشاء السلسلة سيؤدّي ذلك إلى حدوث خطأ ولن يتمّ تنفيذ الأمر. لذلك فالطريقة الصحيحة لكتابة هذه السلسلة هو استخدام علامة الاقتباس المزدوجة: "I'm learning Ruby" مثال آخر: puts '"Never memorize something that you can look up." -Albert Einstein' خيار آخر لاستخدام علامات الاقتباس في السلاسل يسمّى هروب علامة الاقتباس escaping، يحدث هذا عن طريق وضع خط مائل عكسي Backslash قبل علامة الاقتباس والذي سيؤدّي إلى اعتبارها حرفًا عاديًّا بدلاً من تنفيذها كوسيلة لإنشاء سلسلة. يمكن إذًا كتابة السلسلتين السّابقتين كالتّالي: 'I\'m learning Ruby" "\"Never memorize something that you can look up.\" -Albert Einstein" ذكرنا في الدّرس الأوّل أنّ كل شيء في روبي هو كائن Object. يمكن للكائنات تنفيذ أفعال يُطلق عليها اسم دوال. هناك الكثير من الطرق لجعل كائن ينفّذ دالّة ولكن الطريقة الأكثر شيوعًا هي التنويت النُقطي Dot Notation وهو عبارة عن أن تكتب الكائن (في مثالنا هذا الكائن هو السلسلة "Hello Ruby") متبوع بنقطة ثم اسم الدّالة التي تريد استدعاءها. لنجرّب استدعاء الدّالة length والتي هي دالّة مدمجة في روبي تقوم بإرجاع طول السلسلة أو بمعنى آخر عدد الأحرف الموجودة في السلسلة: "Hello Ruby".length المتغيرات أحد أقوى السمات في أيّ لغة برمجة هي القدرة على التعامل مع المتغيّرات. المتغيّر ببساطة هو عنوان (أو "اسم") يشير إلى قيمة معيّنة. بمعنى آخر فالمتغيّر هو طريقة لحفظ الكائنات في الذّاكرة من أجل الاستخدام لاحقًا. يمكن في روبي تعيين متغيّر إلى كائن بسهولة باستخدام عامل التساوي (Equals Operator =): name = "Sara" في هذا المثال، اسم المتغيّر يشير إلى السلسلة "Sara". يعني هذا أنّه بإمكاننا استدعاء دوال مختلفة مباشرةً على اسم المتغيّر بدلاً من كتابة السلسلة في كلّ مرة أردنا استدعاء دالّة. الآن إذا أردت استدعاء الدّالة length لحساب طول السلسلة يمكن ببساطة كتابة ذلك كالتّالي: name.length لنجرّب الآن بعض دوّال روبي التي يمكن استخدامها مع السّلاسل في روبي (السّلاسل عبارة عن كائنات في روبي) على هذا المتغيّر. على سبيل المثال، دالّة reverse ستقوم بطباعة السلسلة معكوسة: name.reverse دوال upcase و downcase من الدوال الخاصّة بالسلاسل أيضًا دالّتا upcase و downcase. تقوم دالّة upcase بتحويل كل الأحرف الموجودة في السلسلة النصيّة إلى أحرف كبيرة Capital Letters. أمّا دالّة downcase فتحوّل كل الأحرف الموجودة في السلسلة إلى أحرف صغيرة Small Letters. جرّب استدعاء الدّالتين على المتغيّر name: name.upcase name.downcase هناك عدد كبير جدًا من الدوال الخاصّة بالسلاسل يمكنك التعرّف على جميعها عن طريق استخدام دالّة methods (نعم هذا هو اسمها) على المتغيّر الخاصّ بك، هكذا: name.methods عند تنفيذ الأمر ستقوم روبي بعرض جميع الدوال المختلفة التي يمكن لهذا النوع من الكائنات استخدامها. يمكنك أيضًا معرفة أكثر عن تلك الدوال عن طريق قراءة التوثيقات الخاصّة بها. دوال Bang ربّما لاحظت أن جميع الدوال التي استخدمناها حتّى الآن لم تغيّر شيئًا في السلسلة، فمثلاً إذا أردتُ معرفة القيمة الموجودة في المتغيّر name من جديد سأجد أن القيمة ما زالت كما عيّنتها من البداية (لمعرفة قيمة متغيّرك فقط اكتب اسم المتغيّر واضغط Enter أو استخدم puts إن أردت). لم تتغيّر القيمة وتصبح السلسلة معكوسة ولا جميع الحروف كبيرة أو صغيرة. لكن ماذا لو أردت فعلاً تغيير تلك القيمة؟ سنجرّب بعض الدوال التي تقوم بالفعل بتغيير قيمة السلسلة. أنشئ متغيّرًا باسم fruit واجعله يساوي السلسلة "apple". يمكن تغيير قيمة ذلك المتغيّر عن طريق استدعاء دوال تسمّى بدوال Bang، تنتهي تلك الدوال بعلامة التعجّب أو ما يسمّى برمز Bang. فمثلاً لو أردت تنفيذ الدالة reverse على السلسلة الخاصّة بك وحفظ القيمة الجديدة بدلاً من القيمة الأصليّة يمكن كتابة ذلك ببساطة هكذا: fruit.reverse! عندما نقوم بطباعة المتغيّر بعد ذلك نلاحظ تغيّر القيمة إلى elppa بدلاً من القيمة السّابقة apple. بهذا نكون قد استغنينا تمامًا عن القيمة الأصليّة واستبدلناها بالقيمة الحاليّة. معظم الدوال الخاصّة بالسلاسل لديها دالّة Bang مماثلة. على سبيل المثال هناك أيضًا دالّة Bang مقابلة لدالّة upcase العاديّة. إذًا فيمكننا كتابة: fruit.upcase! سيطبع هذا الأمر قيمة السلسلة بأحرف كبيرة وأيضًا من جديد سيتمّ استبدال القيمة السابقة بالقيمة الجديدة والتي هي ELPPA. إذا كانت هناك علامة تعجّب Bang في نهاية دالّة روبي فهذا غالبًا يعني كن حذرًا، يمكن لهذه الدالّة أن تكون خطرًا. في حالة الأمثلة السّابقة فهي تعني أنّ قيمة السلسلة ستتغيّر فيجب أن تكون حذرًا متى قمت باستخدام هذه الدوال. تسلسل الدوال قد يكون راودك تساؤل حول ماذا لو أردت تنفيذ العديد من الدوال على أحد المتغيّرات، هل يجب كتابة استدعاء الدالّة على المتغيّر لكل دالّة على حدة؟ لحسن الحظّ يمكن استدعاء أكثر من دالة في وقتٍ واحد على نفس المتغيّر. على سبيل المثال إذا عدنا من جديد إلى المتغيّر name وأردنا كتابته معكوسًا وبأحرف كبيرة، يمكن كتابة ذلك تسلسليًّا هكذا: name.reverse.upcase ولكن تذكّر دائمًا أنّه يتمّ تنفيذ الدوال بالترتيب من اليسار إلى اليمين. رغمّ أنّها لا تهمّ في حالة المثال أعلاه، فحتى إذا بدّلنا الترتيب ستكون النتيجة مشابهة. إلا أنّه يمكن أن يتغيّر النّاتج عن النّاتج الذي تتوقعه في حالات أخرى، لذلك يجب التحقّق من الترتيب عند استخدام هذه الطريقة في استدعاء الدوال. إدراج شيفرات برمجية في السلاسل يمكن بطريقة بسيطة جدًا إدراج شيفرات برمجيّة في سلاسل نصيّة وتنفيذ تلك الشيفرات. يمكن فعل ذلك عن طريق وضع الشيفرات البرمجيّة داخل حاضنات Curly Brackets مع إضافة رمز التلبيد Hash في البداية: "Hello my name is #{name}" يطبع هذا نصًا يحتوي على الجملة المكتوبة بالإضافة إلى النصّ الموجود في المتغيّر name الذي قمنا بإنشائه سابقًا. لذلك فالسلسلة السابقة ستصبح "Hello my name is Sara". ما حدث هو أنّه قد تمّ إدراج قيمة المتغيّر name بداخل السلسلة حيث أنّ علامة التلبيد مع الحاضنات تخبر روبي بأن الموجود بينها هو شيفرات يجب على روبي تنفيذها أولاً وليس طباعتها كما هي. هناك أمر مهمّ عليك تذكّره وهو أنّه عند استخدام شيفرات برمجيّة بداخل سلسلة فلا بد من استخدام علامات الاقتباس المزدوجة. إذا استخدمت علامات اقتباس مفردة فسيتمّ طباعة النصّ كما هو {Hello my name is \#{name. والخط المائل هذا يعني أنّه قد تمّ تخطي هذه القيمة وطُبعت كما هي، مثلما رأينا في السّابق مع 'I\'m'. تطبيق عملي الآن بعد التعرّف على المتغيّرات والسلاسل حان الوقت لكتابة برنامج حقيقي باستخدامهما. في هذا البرنامج سيتمّ طباعة سلسلة نصيّة تسأل المستخدم عن اسمه، ثمّ يقوم البرنامج بعد ذلك باستخدام الاسم الذي سيدخله المستخدم لتطبيق بعض الدوال التي تطرّقنا إليها. أوّلاً نحتاج لإنشاء ملفّ روبي، سمّه ما تريد ولكن لا تنس إضافة rb. إلى نهاية اسم الملفّ. لقد أسميتُ ملفّي greetings.rb. بدايةً سنحتاج إلى طباعة رسالة للمستخدم لسؤاله عن اسمه. لفعل ذلك سنستخدم الأمر puts: puts "Hello, what's your name?" بعد ذلك سنحتاج إلى تمكين المستخدم من كتابة اسمه. أمر gets أمر gets هو اختصار لـ get string والذي يقوم بإيقاف البرنامج وانتظار عمليّة إدخال من المستخدم قبل متابعة تنفيذ البرنامج. سيكون المُدخَل عبارة عن سلسلة كما هو واضح من اسم الأمر. إحدى دوال السلاسل دالّة تسمّى chomp يمكن تطبيقها على سلسلة لحذف الحرف الذي يتمّ إضافته افتراضيًّا للسلسلة بعد الضغط على Enter، حيث أنّه عند استقبال إدخال من المستخدم وبضغطه على زرّ Enter يتمّ تلقائيًّا إضافة حرف سطر جديد إلى نهاية السلسلة. إذًا لتمكين المستخدم من إدخال اسمه نحتاج إلى استخدام أمر gets للحصول على المدخل واستدعاء دالّة chomp لحذف الحرف الزائد وحفظ ناتج ذلك في متغيّر لاستخدامه في وقتٍ لاحق. نكتب ذلك في روبي كالآتي: name = gets.chomp وأخيرًا سنقوم بكتابة شيفرات برمجيّة تتعامل مع هذا المدخل وتطبع بعض المعلومات عنه، أضف ما يلي بعد الأمرين السّابقين في ملفّ روبي الخاصّ بك: puts "Hello #{name}. Your name's length is #{name.length}. That's not really long! Your name backwards is #{name.reverse.downcase.capitalize}" ليُصبح كامل الملف على النّحو التّالي: puts "Hello, what's your name?" name = gets.chomp puts "Hello #{name}. Your name's length is #{name.length}. That's not really long! Your name backwards is #{name.reverse.downcase.capitalize}" يقوم هذا الأمر بطباعة سلسلة نصيّة تحتوي على شيفرات برمجيّة تطبع اسم المستخدم، عدد الأحرف في اسم المستخدم واسم المستخدم معكوسًا. لاحظ في الجزء الثالث كيف أضفنا تسلسل دوال من ثلاث دوال، إحداها هي دالّة جديدة تسمّى capitalize. تقوم دالّة capitalize بتغيير الحرف الأوّل فقط من السلسلة وتحويله إلى حرف كبير على عكس دالة upcase التي تحوّل جميع أحرف السلسلة. احفظ الملفّ بعد كتابة الشيفرات البرمجيّة كاملة ثم قم بتنفيذه عن طريق فتح الطرفيّة والتوجّه إلى مسار المجلّد الذي قمت بحفظ الملفّ به ثم كتابة ruby متبوعًا باسم الملف (أي أنه في حالتي سأكتب الأمر ruby greetings.rb)، إذا واجهتك مشكلة في ذلك فراجع كيف قمنا بعمل ذلك في الدّرس الأوّل. خاتمة بهذا نكون قد انتهينا من الدّرس الثاني وتعرفنا على بعض المفاهيم الأساسيّة في روبي. جاء دورك للتطبيق وحدك، قارن ما يفعله البرنامج بالشيفرات البرمجيّة الخاصّة به للتعرّف أكتر على وظيفة كل جزء. طبّق أيضًا استخدام دوال أخرى لم نستخدمها في البرنامج. كذلك ربّما تريد تجربة كتابة اسمك ثنائيًّا أو ثلاثيًّا مع إضافة مسافة بين كل اسم، هل يتمّ حساب المسافة كحرف ضمن الاسم؟ ابحث في الدوال الخاصّة بالسلاسل عن سلسلة تعالج هذا الأمر وطبّقها.
  14. في المصنفات التي تحتوي على أكثر من ورقة عمل، نحتاج أحيانا إلى الرجوع إلى خلية أو نطاق من الخلايا في أوراق متعددة ذات نمط متشابه عند كتابة صيغة ما. في هذه الحالة يمكننا تجّنب الصيغ المعقدة، أو نسخ الخلايا من ورقة إلى أخرى باستخدام المراجع ثلاثية الأبعاد. البنية العامة للصيغة هي: =Function (first worksheet:last worksheet!cell reference) Function: أي دالة تريد استخدامها، كدالة الجمع، المعدل... إلخ. First worksheet: اسم ورقة العمل الأولى في النطاق. Last worksheet: اسم ورقة العمل الأخيرة في النطاق. Cell reference: اسم الخلية التي تريد تطبيق الدالة عليها في جميع الأوراق ضمن النطاق. وسنوضّح طريقة كتابة الصيغة ثلاثية الأبعاد في الأمثلة التالية: مثال1: في هذا المثال لدينا درجات الاختبارات لمجموعة من الطلاب لأربعة أشهر، وقد تم إدخال درجات كل شهر في ورقة منفصلة (... ,Month1, Month2). المطلوب هو حساب قيمة متوسط الدرجات في ورقة منفصلة (Average): سنقوم أولا بتحديد الخلية التي نريد إظهار نتيجة المتوسط فيها، وهي الخلية B2 في الورقة "Average". ثم سنكتب الصيغة التالية: =average( سننتقل إلى الورقة الأولى في النطاق "Month1"، سنلاحظ في شريط الصيغة إدخال اسم الورقة تلقائيا في الصيغة متبوعا بعلامة تعجب (!)، وهذا يدل على استخدام الورقة الأولى كمرجع: بعدها سنحدد أول قيمة نريد إدخالها في دالة المتوسط، وهي درجة الطالب "زيد ثابت" في الشهر الأول، أي الخلية B2 في الورقة "Month1": ثم سنضغط المفتاح Shift وننقر على آخر ورقة في النطاق "Month4" مع الاستمرار بالضغط، ثم Enter لتطبيق الصيغة: وبذلك تم إيجاد قيمة المتوسط لدرجات اختبارات الطالب الأول للأشهر الأربعة في الورقة "Average" (لاحظ الصيغة في شريط الصيغة). أي ببساطة أننا قمنا بإخبار البرنامج أن يقوم بإيجاد المتوسط لجميع القيم في الموقع B2 من الورقة الأولى حتى الورقة الأخيرة في النطاق. بعد ذلك سنقوم باستخدام التعبئة التلقائية لتطبيق الصيغة على بقية الخلايا في الجدول: من فوائد المراجع ثلاثية الأبعاد هي أنّ قيمة المتوسط ستتغير تبعا لأي تحديث نجريه على أي ورقة من أوراق النطاق. ولكي تتوضح الخطوات السابقة أكثر، شاهد الصورة أدناه: مثال2: هذا المثال يحتوي على ثلاثة أوراق. تحتوي الورقة الأولى "الفرع الأول" على مبيعات الفرع الأول لأحد المتاجر لمجموعة من المنتجات، الورقة الثانية "الفرع الثاني" على مبيعات الفرع الثاني... وهكذا. المطلوب هو إيجاد مجموع المبيعات لكل منتج لكل فرع وللأرباع الأربع: سنقوم أولا بتحديد الخلية التي سيظهر فيها ناتج المجموع للمنتج الأول، وهي B4 في الورقة "المجموع"، ثم سنستخدم دالة الجمع بالصيغة التالية: =sum( ثم سننتقل إلى الورقة الأولى "الفرع الأول" ونحدد الخلية B4: نضغط المفتاح Shift ونحدد الورقة الثالثة "الفرع الثالث" مع الاستمرار بالضغط ليتحدد جميع نطاق الأوراق، ثم نضغط Enter لإيجاد النتيجة: وسنستخدم التعبئة التلقائية لتطبيق الصيغة على جميع الخلايا في الجدول. الصورة أدناه توضح خطوات هذا المثال من البداية: فيما يلي مجموعة الدوال التي تدعم استخدام المراجع ثلاثية الأبعاد في اكسل: SUM: لإيجاد مجموع مجموعة من القيم الرقمية AVERAGE: لإيجاد متوسط مجموعة من القيم الرقمية AVERAGEA: لإيجاد متوسط مجموعة من القيم الرقمية، النصية، والمنطقية COUNT: لحساب عدد الخلايا التي تحتوي على أرقام COUNTA: لحساب عدد الخلايا غير الفارغة MAX: لإرجاع أكبر قيمة ضمن مجموعة من الخلايا MAXA: لإرجاع أكبر قيمة ضمن مجموعة من الخلايا، بما فيها النصوص والقيم المنطقية. MIN: لإرجاع أصغر قيمة ضمن مجموعة من الخلايا MINA: لإرجاع أصغر قيمة ضمن مجموعة من الخلايا، بما فيها النصوص والقيم المنطقية. PRODUCT: لإيجاد حاصل ضرب مجموعة من القيم الرقمية STDEV ،STDEVA ،STDEVP ،STDEVPA: لحساب الانحراف المعياري لمجموعة من القيم المحددة استنادا إلى عينة أو لمحتوى بأكمله. VAR ،VARA ،VARP ،VARPA: لإرجاع قيمة التباين لمجموعة من القيم المحدد استنادا إلى عينة أو لمحتوى بأكمله.
  15. ذكرنا سابقا في درس الصيغ والدوال في اكسل أنّه توجد أنواع مختلفة من الدوال، ومصنفة حسب المجالات المختلفة، منها الدوال الهندسية، الدوال المالية، الدوال المنطقية، دوال الوقت والتاريخ...إلخ. سنتحدث في هذا الدرس بشكل مفصل عن دالة IF الشرطية، وهي إحدى الدوال المنطقية. تُستخدم هذه الدالة لإرجاع قيمة محدد إذا تحقق الشرط، وقيمة أخرى إذا لم يتحقق. الصيغة الأساسية لدالة IF هي: IF(logical_test; [value_if_ture]; [value_if_false])logical_test هو الشرط، كمقارنة قيمتين أو خليتين فيما إذا كانت إحدى القيم أكبر من الأخرى، وهذا الشرط مطلوب تحديده في الصيغة.value_if_true هي القيمة التي يتم إرجاعها إذا تحقق الشرط، وتحديدها في الصيغة مطلوب.value_if_false هي القيمة التي يتم إرجاعا إذا لم يتحقق الشرط، وتحديدها في الصيغة اختياري.سنقوم بشرح بعض الأمثلة لتوضيح مفهوم هذه الدالة. مثال 1: في هذا المثال سنشرح أبسط صيغ استخدام دالة IF. في الجدول التالي مجموعة من القيم في عمودين، A وB. المطلوب هو مقارنة القيم في العمودين، وإذا كانت القيم في العمود A أكبر من القيمة في العمود B يتم إرجاع القيمة "نعم" في عمود "النتيجة"، وإلا يتم إرجاع القيم "كلا" في عمود "النتيجة". سنكتب الصيغة في الخلية الأولى من عمود النتيجة، C2: أي أنّ الشرط logical_test هو A2>B2، النتيجة إذا تحقق الشرط value_if_true هي "نعم"، والنتيجة إذا لم يتحقق الشرط value_if_false هي "كلا". بالطبع ستكون النتيجة "نعم" لأن 12 أكبر من 10. سنكرر هذه الصيغة على بقية الخلايا في عمود "النتيجة"، وسنستخدم زر التعبئة في حافة الخلية لتطبيق التعبئة التلقائية: إذا كانت هناك نصوص ضمن الصيغة يجب أن توضع بين علامتي اقتباس كما فعلنا مع الكلمتين "نعم" و "كلا" لأننا نريد إظهارها بصيغة نصوص في النتيجة. مثال 2: في هذا المثال مجموعة من السلع الصيفية والشتوية، والمطلوب هو إرجاع نتيجة الخصم "%50" إذا كانت السلعة صيفية والقيمة "0" إذا كانت السلعة شتوية. سنقوم بكتابة الصيغة في الخلية C2: لاحظ أنه يمكن استخدام النصوص في صيغة الشرط أيضا، لكن يجب أن توضع بين علامتي اقتباس، كما فعلنا مع النص "صيفي". سنقوم بنسخ الصيغة إلى باقي الخلايا باستخدام التعبئة التلقائية: لاحظ أيضا أن نتيجة الخلية C5 خاطئة على الرغم من كتابة الصيغة بصورة صحيحة إذ يجب أن يكون الخصم 50% لأنّ السلعة صيفية. والسبب هو وجود مسافة بادئة إضافية قبل النص "صيفي" لذلك لم نحصل على النتيجة المتوقعة. ولحل هذه المشكلة سنستخدم الدالة TRIM التي تقوم بإزالة كافة المسافات الإضافية بين النصوص، باستثناء المسافات الفردية بين الكلمات. وستكون الصيغة بالشكل التالي: وعند نسخ الصيغة إلى باقي الخلايا ستظهر النتيجة الصحيحة. ذكرنا أن تحديد قيمة value_if_false في الصيغة أمر اختياري، وإذا لم نقم بتحديدها سيتم إرجاع القيمة 0 في كلا الحالتين، إذا تحقق الشرط أو لم يتحقق. دوال IF المتداخلةويُقصد بها دالة IF داخل دالة IF أخرى، وهذه الصيغة تتيح لك اختبار العديد من المعايير وزيادة عدد النتائج المحتملة. وسنوضح طريقة كتابة الصيغة بالمثالين التاليين: مثال 1: في الجدول أدناه مجموعة درجات لمجموعة من الطلاب، والمطلوب هو إرجاع النتيجة "ممتاز" إذا كانت الدرجة أكبر أو تساوي 90، النتيجة "جيد جدا" إذا كانت الدرجة أكبر أو 80-90، النتيجة "جيد" إذا كانت النتيجة أكبر أو تساوي 70-80، النتيجة "متوسط" إذا كانت النتيجة أكبر أو تساوي 60-70، النتيجة "مقبول" إذا كانت النتيجة أكبر أو تساوي 50-60، أو النتيجة "راسب" إذا لم يتحقق الشرط السابق: سنحدد الخلية C2 وسنكتب الصيغة في شريط الصيغة: ستعمل الصيغة كالتالي: سيتم أولا تقييم الشرط الأول وهو إذا كانت قيمة الخلية B2 أكبر أو تساوي 90، فإذا تحقق الشرط سيتم إرجاع النتيجة "ممتاز" وتتوقف. وإذا لم يتحقق ستنتقل إلى الشرط الثاني، وهو إذا كانت القيمة أكبر أو تساوي 80. لكن القيمة أكبر أو تساوي 80 تشتمل على القيم من 80-100، والقيمة من 90-100 يجب أن تكون نتيجتها "ممتاز" وليس "جيد جدا" كيف سيتم الأمر؟ لن يتم احتساب القيم من 90-100 لأن الشرط الأول هو غير متحقق من الأصل، أي أنّ القيم التي يتم تقييمها في الشرط الثاني هي بالفعل أقل من 90. إذا تحقق الشرط الثاني سيتم إرجاع القيمة "جيد جدا" ثم تتوقف الصيغة، وإذا لم يتحقق سيتم الانتقال إلى الشرط الثالث، وهكذا. سنقوم بنسخ الصيغة إلى بقية الخلايا باستخدام التعبئة التلقائية: مثال 2: في الجدول التالي مجموعة من المنتجات المطلوب إيجاد أسعارها بعد الخصم، لكن نسبة الخصم تختلف حسب سنة الإنتاج: سنحدد الخلية D2 لإظهار النتيجة فيها، وسنكتب الصيغة في شريط الصيغة كالتالي: يتم أولا إيجاد مقدار الخصم بضرب السعر بالنسبة 75% إذا كانت سنة الإنتاج (في العمود B) 2011، بالنسبة 50% إذا كانت سنة الإنتاج 2012، وبالنسبة 25% إذا كانت سنة الإنتاج 2013. بعدها يتم طرح مقدار الخصم من السعر الأصلي في عمود "السعر". لم نستخدم قيم سنوات الإنتاج ونسب الخصم بشكل مباشر في الصيغة وإنما قمنا باستخدام الخلايا التي تحتويها كمرجع مطلق absolute reference (أي استخدمنا $G$2 بدلا من 2011، $H$2 بدلا من 75% وهكذا بالنسبة لبقية القيم). والسبب هو ليكون بإمكاننا تغيير هذه القيم لاحقا دون الحاجة إلى إعادة كتابة الصيغة. لاستخدام الخلية كمرجع مطلق اضغط F4 بعد أن تقوم بتحديد الخلية (أو كتابة اسمها) عند كتابتك للصيغة. وكما في المثال السابق ستعمل الصيغة كالتالي: ستقوم أولا بتقييم الشرط الأول، وهو إذا كانت سنة الإنتاج تساوي 2011، فإذا تحقق الشرط ستقوم بضرب السعر بالنسبة 75% وتتوقف ثم تطرح الناتج من السعر الأصلي. وإذا لم يتحقق الشرط ستنتقل إلى الشرط الثاني، وهكذا. سنقوم بنسخ الصيغة إلى بقية الخلايا باستخدام التعبئة التلقائية: ملاحظة: بالإمكان كتابة دالات داخلية حتى 64 دالة في الصيغة الواحدة. استخدام دالة IF مع المعاملات AND أو ORتُستخدم الدالة IF مع الدالة AND لإظهار نتيجة معينة إذا صحت جميع المعطيات. وتُستخدم مع الدالة OR لعرض نتيجة معينة إذا صح جزء واحد على الأقل من المعطيات. تكون البنية العامة لدالة AND كالتالي: AND(argument1; argument2;…)والبنية العامة للدالة OR كالتالي: OR(argument1; argument2;…)يسمى argument الوسيطة (وأفضل تسميته المُعطى). سنستخدم المثال التالي لتوضيح طريقة كتابة الصيغة: في هذا المثال لدينا ثلاثة اختبارات لعدد من الطلاب، والمطلوب هو إرجاع القيمة "نعم" في عمود "جميع التقييمات ممتازة" إذا كانت الدرجات في جميع الاختبارات للطالب الواحد أكبر أو تساوي 90. سنحدد الخلية E2 لعرض النتيجة للطالب الأول وسنكتب الصيغة في شريط الصيغة: ستعمل الصيغة كالتالي: إذا كانت درجة الاختبار الأول ودرجة الاختبار الثاني ودرجة الاختبار الثالث أكبر أو تساوي 90 فسيتم إرجاع القيمة "نعم" في عمود "جميع التقييمات ممتازة". أما إذا كانت إحدى الدرجات أقل من 90 فسيتم إرجاع القيمة "كلا"، حتى ولو كانت بقية الدرجات أكبر أو تساوي 90. سنقوم بنسخ الصيغة إلى بقية الخلايا باستخدام التعبئة التلقائية: أما عمل الدالة OR فهو مشابه لعمل الدالة AND، باستثناء أنها تقوم بإرجاع القيمة "نعم" إذا صح معطى واحد على الأقل من المعطيات، والقيمة "كلا" إذا لم يصح أي من المعطيات. تُكتب الصيغة التي تتضمن دالة IF والمعامل OR كالتالي: بعد كتابة الصيغة سنقوم بنسخها إلى بقية الخلايا بالتعبئة التلقائية: استخدام الدالتين COUNTIFS وSUMIFSCOUNTIFSتستخدم هذه الدالة لتطبيق مجموعة من المعايير على خلايا ضمن نطاق محدد، ثم إيجاد عدد المرات التي تتحقق فيها كافة المعايير. البنية العامة للدالة COUNTIFS هي كالتالي: COUNTIFS([criteria_range1]; criteria1; [criteria_range2]; criteria2];…)criteria_range1 هو نطاق الخلايا التي سيتم تطبيق المعيار الأول عليها، وهو مطلوب في الصيغة.criteria1 هو المعيار الذي سيطبق على نطاق المعايير الأول لتحديد الخلايا التي سيتم حساب عددها فيما لو تحقق، وهو مطلوب في الصيغة أيضا.أما نطاق المعايير الثاني والمعيار الثاني فهي اختيارية في الصيغة. ملاحظة: جميع النطاقات يجب أن تكون بعدد الصفوف والأعمدة نفسه لنطاق المعايير الأول، لكن لا يُشترط أن تكون متجاورة. وكذلك بإمكانك استخدام أحرف البدل wildcard characters مثل النجمة (*) علامة الاستفهام في إنشاء المعايير. مثال: في الجدول أدناه مجموعة من المشاريع التي تبدأ وتنتهي في أوقات محددة. المطلوب هو حساب عدد المشاريع التي تبدأ بعد التاريخ 1/2/2015 وتنتهي قبل التاريخ 1/7/2015. لقد قمنا بكتابة المعايير في جدول منفصل لاستخدمها كمرجع مطلق: لقد استخدمنا المعايير في الخليتين A12 وB12 كمراجع مطلقة ليصبح بإمكاننا تغيير هذه التواريخ لاحقا عند الحاجة دون أن نضطر إلى إعادة كتابة الصيغة من البداية. سنقوم بتحديد نطاق المعايير الأول (criteria_range1 (B2:B9، ثم سنحدد المعيار الأول (criteria1) وسنضغط F4 لاستخدامه كمرجع مطلق. بعدها سنحدد نطاق المعايير الثاني C2:C9، ثم المعيار الثاني كمرجع مطلق، وبذلك تصبح الصيغة لهذا المثال كالتالي: سيتم بتقييم نطاق الخلايا الأول B2:B9 وحساب عدد التواريخ التي تحقق المعيار >1/2/2015، هناك سبعة في هذا المثال؛ جميع المشاريع ماعدا المشروع 7. بعدها سيقوم بفحص تلك التواريخ السبعة وحساب عدد التواريخ التي تحقق المعيار <1/7/2015 وهناك ثلاثة في هذا المثال، المشروع 1، المشروع 3، والمشروع 5. وبالتي ستكون عدد التواريخ التي تحقق المعيارين 3: SUMIFSتستخدم هذه الدالة لجمع القيم في الخلايا التي تحقق عددا من المعايير ضمن نطاق من الخلايا، والبنية العامة لها هي كالتالي: SUMIFS(sum_range, criteria_range1, criteria1, [criteria_range2, criteria2], ...)sum_range هو نطاق الخلايا المطلوب جمع القيم التي تحقق المعايير فيه.criteria_range1 هو نطاق الخلايا الذي سيتم تطبيق المعيار الأول عليه، وهو مطلوب في الصيغة.criteria1 هو المعيار الذي سيطبق على نطاق المعايير الأول لتحديد الخلايا التي سيتم جمعها وهو مطلوب في الصيغة أيضا.أما نطاق المعايير الثاني criteria_range2 والمعيار الثاني criteria1 فهي اختيارية في الصيغة. مثال: في الجدول أدناه مجموعة من الطلبات والمبيعات المصنفة حسب مندوب المبيعات والمنطقة. المطلوب هو إيجاد مجموع المبيعات حسب المنطقة والتي يحقق فيها مندوب المبيعات عدد طلبات أكبر أو يساوي 20. سنقوم أولا بتحديد نطاق المجموع sum_range، وهو نطاق الخلايا D2:D8 وسنستخدمه كمرجع مطلق. ثم سنحدد نطاق المعايير الأول criteria_range1، وهو نطاق الخلايا B2:B8 وسنستخدمه كمرجع مطلق أيضا. أما المعيار الأول فهو "الشمال"، وسنستخدمه كمرجع نسبي relative reference. وأخيرا سنحدد نطاق المعايير الثاني، وهو نطاق الخلايا C2:C8 كمرجع مطلق ثم المعيار الثاني >=20 كمرجع نسبي: سيتم أولا تحديد مندوبي المبيعات الذي يحققون المعيار "الشمال"، وهما "زيد" و"سامي" في هذا المثال. ومن بين مندوبي المبيعات هؤلاء سيتم تحديد أيهما حقق عدد طلبات أكبر أو يساوي 20، وكلاهما قد حقق هذا العدد في هذا المثال. وبالتالي سيتم جمع المبيعات لكليهما. نفس الخطوات تطبق على المعايير "الجنوب"، الشرق"، والغرب" عند نسخ الصيغة باستخدام التعبئة التلقائية: لاحظ أن نتيجة الشرق تركت فارغة، وذلك لأن المعيار الثاني (عدد الطلبات أكبر أو يساوي 20) لا يتحقق. ملاحظة: إنّ معايير [الشمال]، [الجنوب]، [الشرق]، [الغرب] هي في الحقيقة [=الشمال]، [=الجنوب]، [=الشرق]، [=الغرب]. لكننا لم نقم بكتابتها بالصيغة الأخيرة لأنّ معيار [=] هو المعيار الافتراضي في البرنامج، وسيتم اعتماده ما لم يتم تحديد غيره من المعايير. استخدام الدالتين AVERAGEIFS وIFERRORAVERAGEIFSتُستخدم هذه الدالة لإيجاد المتوسط لمجموعة من الخلايا التي تحقق عدد من المعايير، والبنية العامة لها هي: AVERAGEIFS(average_range; criteria_range1; criteria1; [criteria_range2; criteria2]…)average_range هو نطاق الخلايا المطلوب إيجاد متوسط قيمها. ويتم تجاهل الخلايا الفارغة أو القيم النصية. وهو مطلوب في الصيغة.criteria_range1 هو نطاق المعايير الأول الذي يتم تطبيق المعيار الأول عليه، وهو مطلوب في الصيغة.criteria1 المعيار الذي يتم على أساسه تقييم نطاق المعايير الأول، وهو مطلوب في الصيغة أيضا.أما نطاق المعايير الثاني criteria_range2 والمعيار الثاني criteria1 فهي اختيارية في الصيغة. مثال: سنستخدم المثال السابق لتطبيق دالة AVERAGEIFS. لكن باختلاف المطلوب، وهو إيجاد متوسط المبيعات حسب المنطقة والتي يحقق فيها مندوب المبيعات عدد طلبات أكبر أو يساوي 20. سنقوم أولا بتحديد نطاق المتوسط average_range، وهو نطاق الخلايا التي نريد تطبيق دالة ANERAGEIFS عليها. أي النطاق D2:D8 وسنستخدمه كمرجع مطلق. ثم سنحدد نطاق المعايير الأول criteria_range1، وهو نطاق الخلايا B2:B8 وسنستخدمه كمرجع مطلق أيضا. أما المعيار الأول فهو "الشمال"، وسنستخدمه كمرجع نسبي relative reference. وأخيرا سنحدد نطاق المعايير الثاني، وهو نطاق الخلايا C2:C8 كمرجع مطلق ثم المعيار الثاني >=20 كمرجع نسبي: سيتم أولا تحديد مندوبي المبيعات الذي يحققون المعيار "الشمال"، وهما "زيد" و"سامي" في هذا المثال. ومن بين مندوبي المبيعات هؤلاء سيتم تحديد أيهما حقق عدد طلبات أكبر أو يساوي 20، وكلاهما قد حقق هذا العدد في هذا المثال. وبالتالي سيتم إيجاد متوسط المبيعات لكليهما. نفس الخطوات تطبق على المعايير "الجنوب"، الشرق"، والغرب" عند نسخ الصيغة باستخدام التعبئة التلقائية: لكن كما نلاحظ وجود خطأ القسمة على صفر (DIV/0#!) في الخلية H4، والسبب هو أنّ كلا المعيارين لم يتحققا. فمن منطقة الشرق يوجد أحمد فقط، وعدد الطلبات الذي حققه أصغر من 20. لذلك حصل هذا الخطأ. إذ تقوم دالة AVERAGEIFS بإرجاع القيمة صفر إذا لم تتحقق جميع المعايير. ولإصلاح هذا الخطأ (وغيرها من الأخطاء التي يمكن أن تحصل) سنستخدم الدالة IFERROR. IFERRORتستخدم هذه الدالة لإرجاع قيمة نقوم بتحديدها إذا كان ناتج الصيغة خطأ، أو إرجاع نتيجة الصيغة إذا كانت صحيحة. البنية العامة لهذه الدالة هي: IFERROR(value, value_if_error)value هي القيمة التي يتم فحصها بحثا عن الخطأ.value_if_error هي القيمة التي يتم إرجاعها عند وجود خطأ في الصيغة.سنقوم بإدخال هذه الدالة مع دالة AVERAGEIFS وبالصيغة التالية: في هذا المثال تمثل دالة AVERAGEIFS قيمة value التي يتم فحصها بحثا عن الخطأ. و"لا يوجد متوسط" هي قيمة value_if_error التي يتم إرجاعها عند عدم وجود قيم لإيجاد المتوسط. سنستخدم التعبئة التلقائية لنسخ الصيغة إلى بقية الخلايا:
  16. SASS و Compass هما أداتان تساعدانك على كتابة شيفرة CSS أفضل وبشكل أسرع، ويوجد بهما ما يسمى بالـmixins وهناك أيضًا الدّوال (functions). الـmixins والدّوال ببساطة هي مجموعة من شيفرة CSS التي تقوم بتعريفها/كتابتها مرة واحدة وبعدها يمكنك استخدامها في أي مكان تريده. الفرق بين الـmixin والدالة هو أن الأولى تقوم بمناداتها باستخدام include@ وبعدها يتم ادخال الشيفرة الموجود بها في المكان الذي تمت مناداتها فيه، أما الدالة فلا تحتاج لكتابة كلمة معينة لمناداتها وتقوم بإرجاع قيمة معينة. يمكنك أن تقرأ المزيد حول الفرق بينهما من هنا. Compass هي مكتبة تحتوي على مجموعة من الـmixins الخاصة بـSASS وبها العديد من الأمور المفيدة مثل border-radius و box-shadow. ولكن يمكنك بكل تأكيد أن تقوم بإنشاء mixins ودوال خاصة بك، وهذه بعضها والتي أقوم باستخدامها في كل مشروع أعمل عليه. تأثير أبيض وأسودلنقل أنك تريد نصًا بلون أبيض وبشفافية 90% على خلفية سوداء بشفافية 15%. في حالة كتابة شيفرة CSS كالمعتاد سيكون لديك شيء كهذا: .my-class{ background:rgba(0,0,0,0.15); color:rgba(255,255,255,0.9); }ولكن مع SASS يمكننا كتابة دالتين مفيدتين كالتالي: @function black($opacity){ @return rgba(0,0,0,$opacity) } @function white($opacity){ @return rgba(255,255,255,$opacity) }الآن كل ما سنحتاج لكتابته هو: .my-class{ background:black(0.15); color:white(0.9); }فكما ترى هذا سيوفر علينا بعض الوقت والجهد في كتابة شيفرة CSS اعتيادية ويمكننا كذلك أن نستخدم تلك الدوال في أي مكان نريده حتى نخرج بنفس النتيجة. تأثيرا Emboss وLetterpressصحيح أن عالم التصميم أصبح يبتعد عن التصاميم المزخرفة التي تجعل الأشياء تبدو شبه حقيقة وذلك بسبب ظهور التصميم المسطح، إلّا أنّك في بعض الأحيان تحتاج إلى بعض الظلال أو شيء من هذا القبيل في تصاميمك. المشكلة الوحيدة هي أنّ الظلال في CSS ليست بتلك الجودة وسهولة الاستخدام، ولذلك فإنّ Compass تحتوي على mixin تحمل الاسم box-shadow لتسهل علينا استخدامها، ومع ذلك أعتقد أنه يمكننا أن نقوم بإنشاء شيء أفضل. إذا قمت بتصفح موقع Dribbble فسوف ترى أن 90% من التصاميم التي تحتوي على ظلال تكون تقريبًا بنفس النوع، بحيث يكون هناك خطين بحجم 1px موضوعين أسفل وأعلى التصميم لإعطاء المستخدم انطباعًا وكأنّ ذلك الجزء من التصميم منقوش/محفور في التصميم. أنظر الى الصورة التالية لتفهم ما أعنيه: وهذه mixin بسيطة يمكنك استخدامها لإنشاء ذلك النوع من التأثيرات بسهولة: @mixin box-emboss($opacity, $opacity2){ box-shadow:white($opacity) 0 1px 0, inset black($opacity2) 0 1px 0; }والآن كل ما عليك فعله للحصول على ذلك التأثير هو أن تقوم بالتالي: .box{ @include box-emboss(0.8, 0.05); }وهناك تأثير مشابه يسمى Letterpress وهو نفس التأثير السابق ولكن عندما يتم تطبيقه على النصوص، فالخط الأبيض لا يقوم فقط بالمساعدة في إنشاء ذلك التأثير وإنما يجعل النص مقروءًا أكثر. وها هي الـmixin التي تقوم بذلك: @mixin letterpress($opacity){ text-shadow:white($opacity) 0 1px 0; } إخفاء النصوص واستبدال الصورإلى الآن كل ما قمنا باستخدامه كان على العناصر والتأثيرات البصرية، ولكن الـmixins يمكنها أيضًا مساعدتنا في القيام ببعض الأمور المخفية والمتعبة في CSS. فمن أحد الامثلة الشائعة هو استبدال النص بصورة باستخدام خاصية background في CSS. عادةً يتم استبدال الشعارات (logos) والأزرار (buttons) باستخدام هذه الطريقة. هذه هي الـmixin التي نريدها: @mixin hide-text{ overflow:hidden; text-indent:-9000px; display:block; }ويمكن استخدامها هكذا: .logo{ background: url("logo.png"); height:100px; width:200px; @include hide-text; }وكما هو الحال في كل شيء متعلق بتطوير الويب فإن المتصفحات تتطور أيضًا وتحدث تغيرات كثيرة بسرعة. فالطريقة الموضحة بالأعلى يمكننا استبدالها بطريقة أفضل ويمكنك قراءة هذه المقالة للتعرف على هذه الطريقة. تخيّل لو أننا أردنا أن نقوم باستبدال الطريقة الأولى بالثانية فقط باستخدام CSS الاعتيادي، فعندها كنا سنحتاج إلى أن نقوم باستبدال جميع الشيفرات يدويًا، أمّا مع الـmixin فإنه يمكننا ببساطة تغيير محتويات الـmixin أو التعديل عليها وسوف ينطبق التعديل/التغيير على جميع الشيفرات وفي جميع الأماكن التي استخدمنا فيها الـmixin. أنظر إلى نفس الـmixin الموجود في الأعلى ولكن بتغيير محتوياته إلى الطريقة الثانية (الموجودة في المقال الذي وضعت رابطه بالأعلى): @mixin hide-text{ font: 0/0 a; text-shadow: none; color: transparent; } قوائم التنقل الأفقية (horizontal navigations)شيء آخر نستخدمه كثيرًا وهو استخدام عناصر ul و li لبناء القوائم الأفقية، وهذا في العادة يحتاج منا أن نقوم بتجريد هذه العناصر من بعض تنسيقاتها لنضع تنسيقات خاصة بنا ومفيدة أكثر وحتى نستطيع أيضًا أن نجعل عناصر القائمة تظهر بجانب بعضها بشكل أفقي. فبدلًا من كتابة الشيفرة في كل مرة ولكل قائمة فإننا نستخدم mixin كالتالي: @mixin navigation-list { list-style-type:none; padding:0; margin:0; overflow:hidden; > li{ display:block; float:left; &:last-child{ margin-right:0px; } } }يمكنك أن ترى من هذه الـmixin مبدئين من مبادئ الـSASS وهما القواعد المتداخلة (nested rules) وإشارة "&". القواعد المتداخلة تعني أنك لن تحتاج إلى كتابة العنصر الأب في كل مرة، فمثلًا الشيفرة التالية: ul{ color:red; } ul li{ font-weight:bold; }يمكن كتابتها هكذا: ul{ color:red; li{ font-weight:bold; } }وإشارة "&" هي عبارة عن اختصار للعنصر الحالي، ففي الشيفرة التالية تدل إشارة "&" على العنصر "a.my-link": a.my-link{ color:red; &:hover{ color:blue; } }وبالعودة إلى مثال القائمة يمكنك أن ترى كيف أنّ mixin واحدة يمكنها التأثير على أكثر من عنصر في نفس الوقت، وعندما تقوم بدمجها مع اشارة "&" فتستطيع عندها القيام بالكثير من الأمور المفيدة والرائعة. ترجمة -وبتصرّف- للمقال Useful SASS Mixins لصاحبه Sacha Greif.
  17. ما إن تقضي وقتًا أطول مع لينكس حتى تألف العمل مع سطر الأوامر command line والمعروف أيضًا بالطرفيّة Terminal، وشيئًا فشيئًا ستجد أن الأوامر التي تستخدمها تتكرر ذاتها في كلّ يوم، وأن استعمالاتك لا تخرج عن دائرة صغيرة جدًا من الأوامر والتعليمات المتاحة بالفعل. وقد اجتهد مبرمجو معظم الأوامر والأدوات المستخدمة في الطرفية باختصار طرق استدعائها والعمل من خلالها (تخيّل كم توفّر من نقرات لوحة المفاتيح بكتابة "cd" بدلًا من "change-directory"، أو "ls" بدلًا من "list")، إلا أنّ هذا ليس كل شيء بالطبع، فمعظمنا يستخدم الأوامر مع مجموعة من خياراته المفضّلة. لحسن الحظّ فإن حلًا رائعًا لا يزال بانتظارك؛ حيث تسمح لك الطرفيّة بإنشاء اختصاراتك الخاصّة وحفظ وقتك من خلال ما يسمى بالأسماء المستعارة Aliases والدوال Functions. نناقش في هذا الدرس كيفيّة إنشاء هذه الاختصارات وحفظها بشكل دائم، مع بعض الأمثلة المفيدة التي ستيسر لك عملك بالتأكيد. الإعلان عن اسم مستعار Aliasإنشاء الأسماء المستعارة في الطرفيّة أمرٌ في غاية السهولة، لدرجة أنه يمكنك تجريبه على الفور، يتمّ ذلك باستخدام الأداة alias متبوعة بالاختصار الذي ترغب به، والتي تعرّف اسمًا مستعارًا فعّالا ضمن نافذة الطرفيّة المستخدمة فقط: alias alias_name="command_to_run"انتبه إلى أن أسلوب الكتابة السابق لا يتضمن مسافات فارغة قبل وبعد إشارة المساواة (=)، وهذا ليس أمرًا اختياريًا وإلا فإن الاختصار لن يعمل. لننشئ الآن اسمًا مستعارًا كتجربة، حيث سنأخذ واحدًا من أكثر الأوامر استخدامًا على لينكس وليكن الأمر lsمع الخيار -lha أو -lhA (يهمل الثاني عرض المجلد الحالي ومجلده الأب ضمن الخرج، خلاف الخيار الأوّل)، سنختار له اسمًا مستعارًا وليكن ll: alias ll="ls -lhA"يمكننا الآن كتابة ll للحصول على قائمة بمحتويات المجلد الحالي ضمن قائمة طويلة تتضمن المجلدات المخفيّة: ll -rw-r--r-- 1 root root 3.0K Mar 20 18:03 .bash_history -rw-r--r-- 1 root root 3.1K Apr 19 2012 .bashrc drwx------ 2 root root 4.0K Oct 24 14:45 .cache drwx------ 2 root root 4.0K Mar 20 18:00 .gnupg -rw-r--r-- 1 root root 0 Oct 24 17:03 .mysql_history -rw-r--r-- 1 root root 140 Apr 19 2012 .profile drwx------ 2 root root 4.0K Oct 24 14:21 .ssh -rw------- 1 root root 3.5K Mar 20 17:24 .viminfoوفي حال رغبت بالتوقف عن استخدام الاختصار يمكنك تطبيق الأمر التالي: unalias llوهكذا تُحذف قاعدة الاختصار التي أنشأتها للتوّ. بينما يمكنك الهروب من قاعدة ما بشكل مؤقت عن طريق كتابة رمز الهروب "\" قبل الأمر، فلو قمت بإنشاء قاعدة تحيل الأمر ls إلى الأمر ls -a، وترغب الآن بتطبيق الأمر ls دون استدعاء قاعدة الاختصار، فيمكنك كتابة: \lsيمكنك استعراض جميع القواعد المنشأة في أي وقت من خلال الأمر: aliasلكن كما ذكرنا سابقًا فإن الأسماء المستعارة التي يتم إنشاؤها عن طريق الأداة alias لن تعمل سوى في نافذة الطرفيّة المستخدمة، وهذا يعني أنك لو فتحت نافذة أخرى واستدعيت قاعدة ما فلن تحصل على المطلوب. ولجعل هذه التغييرات دائمة، نحن بحاجة إلى وضعها ضمن أحد الملفات التي تقرأها الطرفية في بداية كل تشغيل لها، الخيارات الشائعة لذلك هي استخدام الملف ~/.bashrc أو ~/.bash_profile، وكل ما علينا فعله هو تحرير أحد هذه الملفات وتعريف قواعد اختصارنا هناك: nano ~/.bashrcالآن أضف الأسماء المستعارة التي كنا قد كتبناها في الطرفيّة بذات الصياغة، يمكنك إضافتها في أسفل الملف، أو في أي مكان آخر، كما يمكنك استخدام التعليقات (بالعلامة #) لتوضيح ما قمتُ بإضافته: ######### # Aliases ######### alias ll="ls -lhA"قد تلاحظ وجود بعض الأسماء المستعارة بالفعل ضمن الملف السابق، حيث تأتي العديد من التوزيعات مع بعض الاختصارات التي تجعل من استخدام الطرفية أمرًا أكثر فاعليّة وسهولة. بعد حفظ الملف تصبح التعديلات المُدخلة جاهزة للاستخدام عند فتح نافذة طرفية جديدة، أما لو رغبت باستعمال قواعد الاختصار الجديدة ضمن نافذة الطرفية الحاليّة فيمكنك كتابة الأمر التالي لإعادة قراءة الملف .bashrc: source ~/.bashrc أمثلة أخرىلنمضي الآن في تعلّم بعض الأمثلة الأخرى عن إنشاء اختصارات تسهّل تعاملك مع الطرفيّة وتجعله أكثر فاعلية، تذكّر دومًا أنه يمكنك البحث في الإنترنت عن استخدامات أخرى نافعة للاختصارات، وإلقاء نظرة على تلك التي قد تكون مُعدّة بشكل افتراضي ضمن إعدادات توزيعتك. التنقل والاستعراضيمكن بإضافة بعض الخيارات على أوامر لينكس البسيطة والشائعة الحصول على نتائج أفضل وأكثر تخصيصًا، رأينا ذلك سابقًا مع الأمر ls، لكن هناك بالتأكيد ما هو أبعد من ذلك. فمثلًا يتيح لنا الاختصار التالي استخدام الخيار -CF مع الأمر ls بشكل افتراضي، والذي يفرّق أثناء العرض بين الملفات والمجلدات، بإضافة الرمز "/" في نهاية اسم كلّ مجلد: alias ls="ls -CF"كما يمكننا الالتفاف حول بعض الأخطاء الكتابيّة الشائعة بالنسبة لنا لجعلها تعمل أيضًا: alias sl="ls"يُنشئ الأمر التالي قاعدة اختصار تُمرّر مخرجات الأمر ls إلى الأداة less لاستعراض محتويات المجلدات الكبيرة بأسلوب مريح: alias lsl="ls -lhFA | less"واحدة من الأخطاء المطبعيّة الشائعة نسيان المسافة بين الأمر cd والنقطتين ..، هذه قاعدة تخرجنا من ذلك المأزق: alias cd..="cd .."أو يمكننا اختصار الأمر بالشكل التالي: alias ..="cd .."وهذه قاعدة أخرى لإنشاء اسم مستعار يسهّل عملية البحث عن الملفات: alias fhere="find . -name "إدارة النظاميحتاج مديرو الأنظمة العاملة بلينكس إلى استخدام الكثير من الأوامر مع تفضيلاتهم الخاصة باستمرار، وهذه فرصة جديدة لتعلّم وإنشاء بعض الاختصارات. تتيح القاعدة التالية إنشاء اسم مستعار يسهّل عرض أقسام واستخدامات القرص الصلب لديك ومعلومات أخرى عنه بطريقة مرتبة باستخدام الأمر df: alias df="df -Tha --total"ويمكن تطبيق نفس القاعدة مع كل من الأمر du والأمر free: alias du="du -ach | sort -h" alias free="free -mt"يستخدم الأمر ps لعرض العمليات والبرامج التي يقوم لينكس بتشغيلها مع معلومات تفصيلية عن كل برنامج، يمكن تسهيل قراءة الخرج من خلال الاختصار التالي: alias ps="ps auxf"كما يمكن إنشاء قاعدة تتيح لنا البحث ضمن جدول الخرج عن عملية محدّدة للاكتفاء بعرضها فقط مما يوفر لنا الوقت: alias psg="ps aux | grep -v grep | grep -i -e VSZ -e"فمثلًا للحصول على معلومات العملية bash فقط يمكن كتابة الأمر التالي: psg bash USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND 1001 5227 0.0 0.0 26320 3376 pts/0 Ss 16:29 0:00 bashأمثلة إضافيّةيعمل الأمر mkdir على إنشاء مجلّد جديد، لكن عند اختيار اسم لمجلد موجود بالفعل يعيد لنا رسالة خطأ، يمكن استخدام الخيار -p مع الأمر السابق لإهمال تلك الرسالة (ودون إنشاء المجلد)، كما يمكن عن طريق قاعدة الاختصار التالية جعل هذا الخيار افتراضيًا: alias mkdir="mkdir -p"أيضًا بإضافة الخيار v إلى الأمر السابق نحصل على المزيد من التنسيق، ففي حال وجود مجلد بذات الاسم يتم تجاهل الأمر وعدم عرض رسالة خطأ، أما لو كان الاسم غير مُستخدم فيعيد الأمر السابق خرجًا على الشاشة يؤكّد عملية إنشاء المجلد بنجاح: alias mkdir="mkdir -pv"في معظم الحالات التي نستخدم بها الأمر wget لتحميل ملف ما من الويب فإننا غالبا ما نمرّر له الخيار -c لدعم استكمال التنزيل في حال حدوث خطأ بالاتصال، لجعل ذلك افتراضيًا ننشئ القاعدة التالية: alias wget="wget -c"يعتبر الأمر history واحدًا من الأدوات الفعّالة، حيث يتيح لك البحث ضمن الأوامر التي سبق واستخدمتها، ويطبع لك النتائج المطابقة على الشاشة مرفقة بأرقامها التسلسليّة (حسب التنفيذ)، حيث يمكن استدعاء الأمر مجددًا من رقمه مسبوقًا بإشارة (!): alias histg="history | grep"كما هو معروف، تتوفر بعض أدوات الطرفية بنسختين، تكون الأولى أكثر بساطة، فيما تقدّم الأخرى ميزات وخدمات أكثر، ومن خلال إنشاء الاختصارات سيكون بإمكانك تشغيل النسخة المحسّنة بنفس أمر تشغيل النسخة الأولى. فالأمر top على سبيل المثال يملك نسخة محسنة وملونة بالاسم htop (إذا لم تكن لديك ركبّها من مدير الحزم في توزيعتك أولًا)، وبإنشاء قاعدة الاختصار التالي نعمّم استخدام النسخة المحسنة في كل التطبيقات الأخرى التي تستعملها: alias top="htop"تقدّم الأداة ncdu عرضًا تحليليًا لاستخدام مساحة القرص، الملفات والمجلدات في لينكس بأسلوب تفاعليّ وخيارات متنوّعة: alias du="ncdu"يستبدل الأمر السابق الأداة du بالأداة ncdu، كما يمكن استبدال الأداة df بـ pydf المحسّنة من خلال: alias df="pydf"هل ترغب في معرفة رقم الـ IP الخاص بجهازك؟ أنشئ القاعدة التالية: alias myip="curl http://ipecho.net/plain; echo"فكّر دومًا كيف يمكنك الاستفادة من القوّة الرهيبة للأسماء المستعارة، على سبيل المثال إذا كنتَ تدير موقعًا على الإنترنت بينما يلزمك باستمرار إعادة تحجيم الصور التي ترغب برفعها إلى الموقع لتناسب مقاسًا مخصصًا، يمكنك تركيب الأداة imagemagick من مدير الحزم في توزيعتك، وإنشاء قاعدة تسهل عليك العمل: alias webify="mogrify -resize 690\> *.png"حالما تطبّق الأمر الجديد webify سيتم إعادة تحجيم جميع الصور الموجودة ضمن المجلّد النشط عندما يكون عرضها أصغر من 690px. وبذات الطريقة يمكنك تسهيل رفعها إلى الخادوم الخاص بك: alias upload="sftp username@server.com:/path/to/upload/directoryالدوالكما رأينا فإن ميزة الأسماء المستعارة توفّر أسلوبًا رائعًا في اختصار تنفيذ الأوامر وتسهيل مراكبتها، إلا أنها في النهاية محدودة القدرة، إذا لا يمكننا على سبيل المثال تطبيق سلسلة طويلة من الأوامر معًا في اختصارٍ واحد. لحسن الحظ فهناك ما يساعدنا لتلبية هذه المتطلبات، تُقدّم الدوال functions أسلوبًا بسيطًا في اختصار تنفيذ قطعة من الأوامر دفعة واحدة، وهي أسلوب يقع بين ميزة الأسماء المستعارة وبين كتابة النصوص التنفيذيّة shell scripts، وتعمل بذات طريقة الأسماء المستعارة، كما يمكنها استقبال الدخل من المستخدم لمعالجته. سنتحدث في هذه الفقرة عن الاستخدامات الأساسية لميزة كتابة الدوال، مع بعض الأمثلة التوضيحيّة، متجنبين التفاصيل الواسعة لها، والتي يمكن من خلالها برمجة نصوص تنفيذيّة متقدّمة. لتعريف دالّة لدينا أسلوبين أساسيين، يستخدم الأوّل الأمر function ويأخذ الشكل العام كالتالي: function function_name { command1 command2 } بينا يشبه الأسلوب الآخر نمط الأقواس في لغة C: function_name () { command1 command2 }يمكن ضغط مساحة الأسلوب السابق ليُكتب في سطر واحد باستخدام الفاصلة المنقوطة بين الأوامر، انتبه إلى أن الفاصلة المنقوطة يجب أن تلتصق بالأمر الذي يسبقها: function_name () { command1; command2; }لنبدأ مع مثال بسيط، عادةً عندما نقوم بإنشاء مجلد جديد ضمن الطرفية فإن الخطوة التالية مباشرة هي الدخول إليه، سنكتب دالة لذلك؛ تنشئ مجلد جديد ثم تنتقل إليه: mcd () { mkdir -p $1 cd $1 }الآن يمكن استخدام الدالة mcd بدلًا من mkdir ثم cd: mcd test pwd /home/demouser/testالدالة التالية تعرض مثالًا متقدمًا على ما يمكن كتابته وتنفيذه عن طريق الطرفية، وهي تعمل على فكّ ضغط أنواع كثيرة من تنسيقات الملفات المضغوطة: function extract { if [ -z "$1" ]; then # display usage if no parameters given echo "Usage: extract <path/file_name>.<zip|rar|bz2|gz|tar|tbz2|tgz|Z|7z|xz|ex|tar.bz2|tar.gz|tar.xz>" else if [ -f $1 ] ; then # NAME=${1%.*} # mkdir $NAME && cd $NAME case $1 in *.tar.bz2) tar xvjf ../$1 ;; *.tar.gz) tar xvzf ../$1 ;; *.tar.xz) tar xvJf ../$1 ;; *.lzma) unlzma ../$1 ;; *.bz2) bunzip2 ../$1 ;; *.rar) unrar x -ad ../$1 ;; *.gz) gunzip ../$1 ;; *.tar) tar xvf ../$1 ;; *.tbz2) tar xvjf ../$1 ;; *.tgz) tar xvzf ../$1 ;; *.zip) unzip ../$1 ;; *.Z) uncompress ../$1 ;; *.7z) 7z x ../$1 ;; *.xz) unxz ../$1 ;; *.exe) cabextract ../$1 ;; *) echo "extract: '$1' - unknown archive method" ;; esac else echo "$1 - file does not exist" fi fi }تعمل الدالة على تحديد تنسيق الملف واختيار الأمر المناسب له للتنفيذ. خاتمةنأمل أن يكون هذا الدرس قد أعطاك بعض الإلهام لكتابة قواعد الاختصار والدوال التي تناسبك، مما يسهّل عليك أداء مهامك الروتينيّة وإضافة بعض المتعة على سطر الأوامر. تذكّر أن تبقى حذرًا من إعادة تعريف بعض الأوامر الأساسية بصوّرة قد تسبب مشاكل أو أخطاء قاتلة، كن حذرًا ولا تنشئ اختصارات تؤثّر على ملفات النظام. نقطة البداية الجيدة هي من سجل الأوامر التي كنتَ قد استخدمتها بالفعل في الفترة الماضية، لترى مالذي يتكرّر باستمرار، وتعمل على اختصار العمل من خلال إنشاء أسماء مستعارة جديدة: history | awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] &quot; &quot; CMD[a]/count*100 &quot;% &quot; a;}' | grep -v &quot;./&quot; | column -c3 -s &quot; &quot; -t | sort -nr | nl | head -n10يعرض السطر السابق خرجًا بالأوامر الأكثر تكرارًا في استخدامك اليوميّ ونسبها المئوية، مما يعطيك الفكرة عن احتياجاتك الحاليّة. نسعد أيضًا بمشاركتكم لنا الاختصارات والدوال التي تستخدمونها عادةً لتبادل الخبرات. ترجمة -وبتصرّف- للمقال An Introduction to Useful Bash Aliases and Functions.
  18. واحدة من أبرز قوى ووردبريس مكتباته التي تحتوي على المئات من دوال PHP، وهذه الدوال لديها وظائف متعددة من كتابة روابط التدوينات والمشاركات داخل الإضافة إلى استرجاع اسم مستخدم كاتب التدوينة والاستعلام عنه في قاعدة البيانات. فإذا لم تفهمهم، ستكون العناصر الأساسية للووردبريس مثل the_post غريبة بالنسبة لك، وسيكون الكود التي تكتبه مليئا بالأخطاء والغرابة. وفي نفس الوقت، عند محاولة استعمال المئات من الدوال ذات أسماء غير نظامية يمكن أن يسبب الإرباك لقارئها، لذا سأقوم اليوم بإعطائك مبدأين أساسيين لفهم دوال ووردبريس. هذه المبادئ المنطقية تطبق بشكل واسع (إذا لم يكن عالميا) على مكتبات الدوال، والتي سوف تعطيك نظرة خاطفة على وظيفة دالة ووردبريس معينة. 1. دوال _get تقوم بإرجاع أشياء و دوال _the تطبع أشياءهذا ملخص بسيط لآلية عمل هذين الدالتين: دوال _get تقوم بإرجاع قيمة، مما يسمح لك بالتعامل معها في تعليمات برمجية لاحقة. دوال _the تقوم بطباعة قيمة في صفحة HTML في المكان الذي تم استدعاؤها فيها.ولتوضيح ذلك، لنلق نظرة على الكود المصدري لدالتين، دالة ()the_ID و دالة ()get_the_ID: function get_the_ID() { post = getpost(); return !empty(post ) ? $post->ID : false; } function the_ID() { echo get_the_ID(); }باختصار، إن دالة ()get_the_ID تقوم بإرجاع مُعرف الرقمي للتدوينة، وأما return فهي تعني: قُم بإعطاء القيمة لمن طلبها”، وعندما تحصل على هذه القيمة، يمكنك القيام بأي شيئ بها، مثلا تقوم بضربها في 3، قسمتها على 2، وغيرها حسب البرنامج، (بالمناسبة إذا كنت تتساءل على بقية الشِفرة البرمجية فإن معناها قُم بإرجاع المُعرف، أو قُم بإرجاع false إذا لم تجد التدوينة التي يجب أن تحصل على مُعرفها). لنفترض أنك ترد تعديل صفحة php، لنأخذ ملف index.php للقالب على سبيل المثال، وتريد أن تقوم بطباعة عنوان التدوينة في الصفحة، هذه بعض الخيارات لتفعل ذلك: <h1><?php get_the_title(); ?></h1> <!-- لن يتم طباعة أي شيئ --> <h1><?php the_title(); ?></h1> <!-- طباعة عنوان التدوينة داخل عنصر h1 --> <h1><?php echo get_the_title(); ?></h1> <!-- طباعة عنوان التدوينة داخل عنصر h1 --> <h1><?php echo 'My title: ' . get_the_title(); ?></h1> <!-- طباعة ": My title" وعنوان التدوينة داخل عنصر h1 -->سيكون مفيدا أن تعرف هذه العلاقة التي تُعقد عبر مكتبة دالة ووردبريس مع استثناء أن ()the_post تقوم بشيء مهم لكنها لا تطبع أي شيئ. 2. داخل أو خارج الحلقة التكراريةالحلقة التكرارية هي النواة التقنية الأساسية لووردبريس، بعض الدوال يجب أن يتم استدعاؤها داخل الحلقة التكرارية، وبعضها لا يجب ذلك، فمثلا هذا المثال يوضح لك ما معناه "دالة داخل الحلقة": //خارج الحلقة التكرارية if ( have_posts() ) : while ( have_posts() ) : the_post(); // داخل الحلقة التكرارية، محتويات التدوينة تكون هنا endwhile; endif; // خارج الحلقة التكرارية مرة أخرىللتمييز بين “دالة داخل الحلقة” و “دالة خارج الحلقة”، سنقوم باستخدام التشبيه لتفسير مكان الحلقة داخل الووردبريس: لنتخذ ووردبريس كمصنع سيارات! ووردبريس هو مصنع السيارات. المشاركات والتدوينات هي السيارات. الحلقة التكرارية هي خط التجميع في المصنع.دعونا نشرح العلاقة بين هذه المصطلحات بمزيد من التفاصيل: خط التجميع تدخل داخله أجزاء السيارات خامة لتخرج سيارة كاملة. بنفس الطريقة، الحلقات التكرارية هي مواد المشاركات الخامة (محتوى المشاركة والبيانات التعريفية) تدخل لتخرج صفحة HTML جاهزة.والآن دعونا نشرح الجزء المهم: كل عملية تقوم بتغيير أو تقوم باسترداد معلومات حول السيارات يجب أن تكون في خط التجميع، ويجب أن يتم الإعلان عن أية سيارة ستعمل بطريقة أخرى، فالعمليات التي لا تعمل على السيارات يجب أن لا تكون في خط التجميع. وبالمثل، كل دالة تقوم باسترداد أو تغيير أو عرض لخصائص التدوينة أو المشاركة يجب أن تكون إما داخل الحلقة التكرارية أو يجب أن يتم إعطاء معرف التدوينة أو المشاركة للتعامل معها كمعامل (paramter) للدالة. الدوال التي لن تعمل عن التدوينات/المشاركات لا يجب أن تكون داخل الحلقة التكرارية. عمليا هذا يعني: إن دوال _the وأغلب دوال _get_the تفترض معرفة التدوينة/المشاركة الحالية لذا سيعملون فقط داخل الحلقة التكرارية. أما في خارج الحلقة التكرارية، يجب إخبار دوال _get_the على أية تدوينة ستعمل، أي يجب تمرير معرفة التدوينة. الدوال التي لا تستخدم لاسترداد أو تغيير أو عرض لخصائص التدوينة/المشاركة يجب أن لا يتم استدعاؤها في الحلقة التكرارية.على خط التجميع: دالة _the_title التي تعمل فقط في الحلقات التكرارية. بالنسبة لآلة الطلاء فإنه يجب على الآلة أن تعرف الكثير من المعلومات حول السيارات قبل البدء بطلائه، ولهذا السبب ستجد هذه الآلة في خط التجميع تحصل على معلومات السيارة الحالية بهذه الطريقة و سوف تكون في المكان الصحيح لطلاء السيارة في الوقت المناسب في المصنع. آلة الطلاء في هذه الحالة هي دالة _the_title، فهي تعمل فقط داخل الحلقة التكرارية، وهي تقوم بطلاء الموقع الذي صممه المصنع لعمل عنوان التدوينة الحالية. لتكون قادرا على الإشارة إلى عنوان تدوينة في موقع ربما يمتلك أكثر من 1000 تدوينة ومشاركة يجب أن نعلم أية تدوينة نريدها بالضبط، والدالة التي تقوم ببساطة بطباعة عنوان التدوينة (بدون خيارات أخرى) لن تؤثر كثيرا خارج سياق الصفحة التي صممت من تلك التدوينة. لذلك فالطريقة الوحيدة لتعمل دالة ()the_title هو وضعها داخل الحلقة التكرارية، مثل الآلة الطلاء التي لا يجب أن تكون في بهو المصنع. داخل أو خارج خط التجميع: ()get_the_title، دالة داخل أو خارج الحلقة التكرارية. دعونا نفترض أنك تريد معرفة لون طلاء لسيارة، وهذا الأمر سيكون ذا أهمية داخل خط التجميع، وفي هذه الحالة سوف تقوم ببناء آلة تقوم بإعطائك لون السيارة التي تمر من أمامها. لكن قد ترغب أيضا بإرسال فريق مراقبة الجودة إلى منطقة الشحن للحصول على لون سيارة معينة، لذلك سوف يحتاج الفريق إلى معرفة أية سيارة سيقومون بتفقدها، وإلا لن يستطيعوا إخبارك بأي شيئ. بكلمات أخرى، يمكنك فعل هذا داخل أو خارج خط التجميع، لكن إذا كنت في الخارج، يجب عليك أن تقوم بخطوة إضافية لتحديد أية سيارة أنت مهتم بها. فمثلا دالة ()get_the_title التي تعمل داخل الحلقة التكرارية بدون إدخال معطيات، أو خارج الحلقة مع إدخال مُعرف التدوينة، كما يلي: get_the_title(); // يتم استدعاؤها داخل الحلقة التكرارية، تقوم بإعطائك عنوان التدوينة الحالية. // استدعاؤها خارج الحلقة لن يفيد. get_the_title(‘121’); // داخل أو خارج الحلقة التكرارية، تقوم بإعطائك عنوان التدوينة مع المُعرف 121.خارج خط التجميع: ()wp_enqueue_script، دالة خارج الحلقة التكرارية. حتى الآن تحدثنا كثيرا حول خط التجميع في المصنع، ومع ذلك، قد يحتوي المصنع أيضا على مستودع ومكتب الاستقبال وقسم الشحن والمكاتب الإدارية وغيرها. ولا أي إدارة من هذه الإدارات تحتاج إلى معرفة أية سيارة يتم العمل عليه الآن، وأنت بالتأكيد لا تريد وضع المكاتب الإدارية مع خط التجميع. وهذا هو نفس الحال مع دالة ()wp_enqueue_script التي لا تفيد داخل الحلقة التكرارية، فهذه الدالة تستعمل لمعرفة أن صفحة ما تم صنعها بواسطة مصدر خاص للووردبريس أو لا. ملفات جافاسكريبت ليست جزءً من التدوينة تم صنعه بواسطة الحلقة التكرارية، فهو لا يتفاعل مع التدوينات بنفس الطريقة التي لا يتفاعل فيها مكتب الحسابات مع السيارات، فعندما توجد شحنة سيارات جاهزة، سوف يتأكد هذا القسم من أن الشحنة لديها فاتورة ملتصقة بها، لكنه بالتأكيد لا يعقل أن يتم إلصاق الفاتورة على أرض المصنع. لذلك لا تقم باستخدام دالة ()wp_enqueue_script في الحلقة التكرارية، وسيكون أفضل لو وضعتها في ملف functions.php للقالب أو للإضافة. قم بالبرمجةحسنا حاولت تسهيل هذا الأمر عن طريق استعمال جميع معرفتي عن مصانع السيارات، و من الأرجح أنني قمت بتوسيع منطقة التشبيهات داخل دماغي، لكن أرجو أنني علمتكم بعض المفاتيح الرئيسية التي سوف تمكنك من الدخول إلى عالم دوال ووردبريس وأنت مطمئن، وإذا كان لديك أي سؤال أو تعليق، فيسرنا أن نسمعه في التعليقات في الأسفل، وإذا أعجبك هذا المقال، أرجو أن تقوم بمشاركتها مع أصدقاءك. ترجمة -وبتصرف- للمقال: Two Key Principles for Understanding WordPress Functions لصاحبه Fred Meyer. حقوق الصورة البارزة: Business vector designed by Freepik.