الدرس الحادي عشر - التعامل مع النصوص

مفهوم النصوص في C++

في عالم البرمجة, نقول للنص "String" سواء كان يتألف من حرف واحد, كلمة, جملة أو نص كبير جداً.
و من هذا المنطلق نستنتج أن النص عبارة عن سلسلة من الأحرف ليس لها حجم محدد.

 

طريقة تعريف متغير نصي

في لغة C++ تم إنشاء النوع string خصيصاً لتخزين القيم النصية و هو موجود في المل std.
لذلك إن لم تقم بتضمين الحزمة std في برنامجك, يجب أن تعرّف النص بهذا الشكل std::string.
بالإضافة إلى ذلك, القيمة النصية يجب وضعها بين علامة التنصيص "" كما في المثال التالي.

مثال

Main.cpp

  1. #include
  2. using namespace std;
  3. int main()
  4. {
  5. // "Hello World!" و قيمته النص s هنا قمنا بتعريف متغير نصي إسمه
  6. string s = "Hello world!";
  7.  
  8. // s هنا قمنا بطباعة قيمة المتغير
  9. cout << s;
  10.  
  11. return 0;
  12. }

•سنحصل على النتيجة التالية عند التشغيل.

  • Hello world!

 

معلومة تقنية

النوع string في الأساس عبارة عن كلاس ( Class ) و ليس كباقي أنواع البيانات الأولية التي تعرفنا عليها سابقاً.
أيضاً, عندما تقوم بتعريف متغير نوعه string فأنت في الواقع تقوم بإنشاء كائن ( Object ) منه.

لا تقلق بتاتاً إن لم تفهم معنى كلاس و كائن الآن لأنك ستتعلم ذلك بتفصيل ممل لاحقاً في الدورة.

 

مفهوم دمج النصوص في C++

دمج النصوص ( Concatenation ) يقصد به وضع سلسلة من النصوص بجانب بعضها لعرضها كنص واحد. و هذا الأمر ستحتاجه في أي تطبيق.

فمثلاً, في البرامج أو المواقع التي تستخدمها تلاحظ أنه عند إنشاء حساب جديد يطلب منك أن تدخل إسمك على مرحلتين كالتالي:
- الإسم ( First Name ).
- إسم العائلة ( Last Name ).

بعد أن تنشئ حسابك تلاحظ أنه قام بعرض إسمك الكامل ( الإسم + إسم العائلة ).
عند وضع الإسمين بجانب بعضهما و كأنهما نص واحد يكون المبرمج فعلياً قد قام بدمجهما فقط و ليس إعادة كتابتهما من جديد.

في المثال التالي سنقوم بتعريف المتغير firstName لنضع فيه الإسم, و المتغير lastName لنضع فيه إسم العائلة, و المتغير fullName لنضع فيه الإسم و إسم العائلة.

مثال

Main.cpp

  1. #include
  2. using namespace std;
  3. int main()
  4. {
  5. // و وضعنا فيه نص يمثل الإسم firstName هنا قمنا بإنشاء المتغير
  6. string firstName = "Mhamad";
  7.  
  8. // و وضعنا فيه نص يمثل إسم العائلة lastName هنا قمنا بإنشاء المتغير
  9. string lastName = "Harmush";
  10.  
  11. // و أضفنا بينهما مسافة فارغة lastName و إسم العائلة الموجود في المتغير firstName و وضعنا فيه الإسم الموجود في المتغير fullName هنا قمنا بإنشاء المتغير
  12. string fullName = firstName + " " + lastName;
  13.  
  14. // و يالتالي سيتم عرض الإسم الكامل الذي قمنا بدمجه و وضعه فيه fullName هنا عرضنا قيمة المتغير
  15. cout << fullName;
  16.  
  17. return 0;
  18. }

•سنحصل على النتيجة التالية عند التشغيل.

  • Mhamad Harmush

 

كيف يتم تخزين النص في C++

لنفترض أننا قمنا بتعريف string إسمه s و أعطيناه قيمة.

مثال

  • string s = "welcome to harmash.com";

 

بما أننا نستخدم أحرف إنجليزية, سيتم تخزين نص المتغير s في الذاكرة حرفاً حرفاً و بالترتيب كما في هذه الصورة التالية.

 

 

مصطلحات تقنية

  • عدد أحرف النص يسمى Length.
  • رقم الخانة يسمى index.
  • أرقام الخانات يقال لها indices أو indexes.
  • إذا قمنا بأخذ جزء من النص فهذا الجزء يسمى substring.

 

أنت كمبرمج يمكنك إستغلال أرقام الخانات لتصل لمحتوى النص كالتالي.

 

 

فكرة الثابت string::npos في C++

هذا المتغير الثابت موجود في الكلاس string و فكرته هي أنك حين تحاول البحث في النص عن قيمة ما و لا تجدها فإنه يتم إرجاع قيمته لك للإشارة إلى أنه قد تم البحث في كل النص و لم يتم إيجاد القيمة التي تبحث عنها.

إنتبه لنقطة مهمة و هي أنك لست مضطر لحفظ قيمته, بل يكفي فقط أن تعرف كيف يتم إستخدامه في الكود.

في المثال التالي, قمنا بإنشاء متغير نوعه string و إسمه s و وضعنا فيه نص.
بعدها إستخدمنا الدالة find() للبحث عن كلمة في النص الموضوع في المتغير s.

لمعرفة ما إن تم إيجاد الكلمة المراد البحث عنها في النص أم لا, قمنا بمقارنة القيمة التي أرجعتها الدالة find() بعد أن إنتهت من البحث مع قيمة المتغير string::npos.
إذا كانت القيمة التي أرجعتها الدالة find() تساوي قيمة المتغير string::npos فهذا يعني أنه لم يتم إيجاد الكلمة المراد البحث عنها. إذا لم تكن تساويها فهذا يعني أنه تم إيجادها.

مثال

Main.cpp

  1. #include
  2. using namespace std;
  3. int main()
  4. {
  5. // s هنا قمنا بتعريف متغير نصي إسمه
  6. string s = "I'm learning c++ from harmash.com";
  7. // result و تخزين نتيجة البحث في المتغير "java" عن الكلمة s هنا قمنا بالبحث في النص الموجود في المتغير
  8. size_t result = s.find("java");
  9. // string::npos مع قيمة result هنا قمنا بمقارنة قيمة
  10. // إذا كانت متساويتين فهذا يعني أنه لم يتم إيجاد الكلمة التي بحثنا عنها
  11. if (result == string::npos)
  12. {
  13. cout << "Word not found!";
  14. }
  15. // إن لم يكونا متساويتين, فهذا يعني أنه تم إيجاده الكلمة التي بحثنا عنها و سيتم طباعة رقم أول خانة تم عنده إيجاد الكلمة
  16. else
  17. {
  18. cout << "Word is found at index " << result;
  19. }
  20.  
  21. return 0;
  22. }

•سنحصل على النتيجة التالية عند التشغيل.

  • Word not found!

 

 

دوال الكلاس string في C++

الجدول التالي يحتوي على دوال الكلاس string الأكثر استخداماً.

إسم الدالة مع تعريفها

 

int length() ترجع رقم يمثل عدد أحرف النص الذي قام باستدعائها.
للدقة, فإن الرقم الذي ترجعه يمثل من كم Byte يتألف النص.

1

int size() ترجع رقم يمثل عدد أحرف النص الذي قام باستدعائها تماماً مثل الدالة length().

2

string substr(int pos=0, int len = npos) ترجع نص عبارة عن جزء من النص (Substring) الذي قام باستدعائها.
مكان الباراميتر pos نمرر index الحرف الذي نريد البدء بنسخ النص من عنده.
مكان الباراميتر len يمكنك تمرير رقم يمثل كم حرف تريد أن تنسخ من عند index الباراميتر pos إن لم ترد نسخ كل النص الموجود.

3

int find(string str) تبحث في النص الذي قام بإستدعائها عن أول index يوجد إبتداءاَ من عنده نفس النص الذي نمرره لها مكان الباراميتر str و ترجعه.

4

int rfind(string str) تبحث في النص الذي قام بإستدعائها عن آخر index يوجد إبتداءاَ من عنده نفس النص الذي نمرره لها مكان الباراميتر str و ترجعه.

5

string replace(int pos, int len, string replacement) تستخدم لتعديل جزء محدد من النص الذي قام باستدعائها.
مكان الباراميتر pos نمرر index الحرف الذي نريد البدء بتغيير النص من عنده.
مكان الباراميتر len نمرر رقم يمثل كم حرف تريد أن تبدل إعتباراً من عند index الباراميتر pos.
مكان الباراميتر replacement نمرر النص الذي سيتم إضافته مكان الجزئية التي سيتم حذفها.

6

void swap(string str) تبدل محتوى النص الذي قام بإستدعائها بمحتوى النص الذي نمرره مكان الباراميتر str.
كما أنها تبدل محتوى المتغير الذي نمرره مكان الباراميتر str بمحتوى النص الذي قام باستدعائها.

7

string append (const string str) تضيف قيمة النص الذي نمرره مكان الباراميتر str في آخر النص الذي قام باستدعائها و ترجع النص الناتج عند دمجهمها معاً.

8

bool empty() ترجع true إذا كان النص الذي قام باستدعائها غير فارغ (أي يوجد فيه حرف على الأقل).
و ترجع false إن لم يكن كذلك.

9

void clear() تمسح كل الأحرف الموجودة في النص الذي قام باستدعائها.

10

int compare (const string str) تقارن حجم النص الذي قام باستدعائها مع حجم النص الذي نمرره لها مكان الباراميتر str.
ترجع 0 في حال كان حجمهم متساوي.
ترجع 1 في حال كان عدد أحرف النص الذي قام باستدعائها أكبر.
ترجع -1 في حال كان عدد أحرف النص الذي قام باستدعائها أصغر.

11

string insert (int pos, const string str) تضيف قيمة النص الذي نمرره مكان الباراميتر str في النص الذي قام باستدعائها عند Index الخانة التي نحددها مكان الباراميتر pos و ترجع النص الناتج عند دمجهمها معاً.

12

 

 

العوامل التي تستخدم لمقارنة النصوص في C++

الجدول التالي يحتوي على العوامل التي يمكن استخدامها لمقارنة أحجام النصوص.

إسم العامل

رمزه

مثال

شرح الكود

Equal to

==

(a == b)

هل قيمة a تساوي قيمة b ؟
إذا كان الجواب نعم فإنها ترجع true

Not equal to

!=

(a != b)

هل قيمة a لا تساوي قيمة b ؟
إذا كان الجواب نعم فإنها ترجع true

Greater than

>

(a > b)

هل قيمة a أكبر من قيمة b ؟
إذا كان الجواب نعم فإنها ترجع true

Less than

<

(a < b)

هل قيمة a أصغر من قيمة b ؟
إذا كان الجواب نعم فإنها ترجع true

Greater than
or Equal to

>=

(a >= b)

هل قيمة a أكبر أو تساوي قيمة b ؟
إذا كان الجواب نعم فإنها ترجع true

Less than
or Equal to

<=

(a <= b)

هل قيمة a أصغر أو تساوي قيمة b ؟
إذا كان الجواب نعم فإنها ترجع true

 

مثال

Main.cpp

  1. #include
  2. using namespace std;
  3. int main()
  4. {
  5. // s2 و متغير نصي إسمه s1 هنا قمنا بتعريف متغير نصي إسمه
  6. string s1 = "harmash";
  7. string s2 = "google";
  8. // سيتم تنفيذ أمر الطباعة s2 يساوي عدد أحرف s1 إذا كان عدد أحرف
  9. if (s1 == s2)
  10. cout << "s1 == s2" << endl;
  11. // سيتم تنفيذ أمر الطباعة s2 أكبر من عدد أحرف s1 إذا كان عدد أحرف
  12. if (s1 > s2)
  13. cout << "s1 > s2" << endl;
  14. // سيتم تنفيذ أمر الطباعة s2 أكبر أو يساوي عدد أحرف s1 إذا كان عدد أحرف
  15. if (s1 >= s2)
  16. cout << "s1 >= s2" << endl;
  17. // سيتم تنفيذ أمر الطباعة s2 أصغر من عدد أحرف s1 إذا كان عدد أحرف
  18. if (s1 < s2)
  19. cout << "s1 < s2" << endl;
  20. // سيتم تنفيذ أمر الطباعة s2 أصغر أو يساوي عدد أحرف s1 إذا كان عدد أحرف
  21. if (s1 <= s2)
  22. cout << "s1 <= s2" << endl;
  23. return 0;
  24. }

•سنحصل على النتيجة التالية عند التشغيل.

  • s1 > s2
  • s1 >= s2