التعامل مع السلاسل النصية في لغة سي++ (C++ String Handling)

نظرة عامة على السلاسل النصية في سي++

في سي++، يتم تمثيل السلاسل النصية باستخدام فئة std::string، وهي جزء من مكتبة القياسية. توفر هذه الفئة مجموعة واسعة من الوظائف والأساليب لمعالجة السلاسل النصية، مثل الإضافة، والمقارنة، والبحث، والتعديل. قبل ظهور فئة std::string، كانت سي++ تعتمد على سلاسل الأحرف المنتهية بالفراغ (char arrays)، لكن std::string تقدم واجهة أكثر سهولة وأمانًا.

إنشاء السلاسل النصية وتهيئتها

يمكن إنشاء سلاسل نصية في سي++ بعدة طرق:

  • باستخدام المُنشئ الافتراضي (Default constructor): يتم إنشاء سلسلة نصية فارغة.
  • باستخدام سلسلة حرفية (String literal): يتم تهيئة السلسلة النصية بقيمة معينة.
  • باستخدام منشئ آخر (Another constructor): يتم إنشاء سلسلة نصية من سلسلة نصية أخرى، أو من جزء من سلسلة أخرى.

أمثلة:


#include <iostream>
#include <string>

int main() {
  // إنشاء سلسلة نصية فارغة
  std::string str1;

  // إنشاء سلسلة نصية باستخدام سلسلة حرفية
  std::string str2 = "Hello, World!";

  // إنشاء سلسلة نصية من سلسلة أخرى
  std::string str3 = str2;

  // إنشاء سلسلة نصية من جزء من سلسلة أخرى
  std::string str4(str2, 0, 5); // "Hello"

  std::cout << "str1: " << str1 << std::endl; // فارغة
  std::cout << "str2: " << str2 << std::endl; // Hello, World!
  std::cout << "str3: " << str3 << std::endl; // Hello, World!
  std::cout << "str4: " << str4 << std::endl; // Hello

  return 0;
}

الوصول إلى عناصر السلسلة النصية

يمكن الوصول إلى أحرف السلسلة النصية فرديًا باستخدام الفهرسة (indexing) أو باستخدام الدالة at(). الفهرسة تبدأ من الصفر، حيث يمثل الفهرس 0 الحرف الأول في السلسلة. الدالة at() توفر فحصًا للحدود، مما يمنع الوصول إلى مواقع خارج نطاق السلسلة ويساعد على تجنب الأخطاء.

أمثلة:


#include <iostream>
#include <string>

int main() {
  std::string str = "Hello";

  // الوصول إلى الحرف الأول باستخدام الفهرسة
  char firstChar = str[0]; // H

  // الوصول إلى الحرف الأخير باستخدام الدالة at()
  char lastChar = str.at(str.length() - 1); // o

  std::cout << "First character: " << firstChar << std::endl;
  std::cout << "Last character: " << lastChar << std::endl;

  // محاولة الوصول خارج النطاق باستخدام at() ستؤدي إلى رمي استثناء
  // str.at(10); // يرمي استثناء out_of_range

  return 0;
}

تعديل السلاسل النصية

توفر فئة std::string العديد من الأساليب لتعديل السلاسل النصية، بما في ذلك:

  • الإضافة (Append): لإضافة سلسلة نصية أو حرف إلى نهاية السلسلة.
  • الإدراج (Insert): لإدراج سلسلة نصية أو حرف في موقع معين.
  • الحذف (Erase): لحذف جزء من السلسلة.
  • الاستبدال (Replace): لاستبدال جزء من السلسلة بسلسلة أخرى.

أمثلة:


#include <iostream>
#include <string>

int main() {
  std::string str = "Hello";

  // الإضافة
  str.append(", World!");
  std::cout << "Append: " << str << std::endl; // Hello, World!

  // الإدراج
  str.insert(5, " beautiful");
  std::cout << "Insert: " << str << std::endl; // Hello beautiful, World!

  // الحذف
  str.erase(5, 10);
  std::cout << "Erase: " << str << std::endl; // Hello, World!

  // الاستبدال
  str.replace(7, 5, "Universe");
  std::cout << "Replace: " << str << std::endl; // Hello, Universe!

  return 0;
}

مقارنة السلاسل النصية

يمكن مقارنة السلاسل النصية باستخدام عوامل المقارنة القياسية (==, !=, <, >, <=, >=) أو باستخدام الدالة compare(). عند استخدام عوامل المقارنة، يتم إجراء مقارنة معجمية (lexicographical comparison)، أي أنها تقارن الأحرف بناءً على ترتيبها في جدول ASCII.

أمثلة:


#include <iostream>
#include <string>

int main() {
  std::string str1 = "apple";
  std::string str2 = "banana";

  // المقارنة باستخدام عوامل المقارنة
  if (str1 == str2) {
    std::cout << "str1 و str2 متساويتان" << std::endl;
  } else if (str1 < str2) {
    std::cout << "str1 أصغر من str2" << std::endl; // سيتم تنفيذه
  } else {
    std::cout << "str1 أكبر من str2" << std::endl;
  }

  // المقارنة باستخدام الدالة compare()
  int result = str1.compare(str2);
  if (result == 0) {
    std::cout << "str1 و str2 متساويتان" << std::endl;
  } else if (result < 0) {
    std::cout << "str1 أصغر من str2" << std::endl;
  } else {
    std::cout << "str1 أكبر من str2" << std::endl;
  }

  return 0;
}

البحث في السلاسل النصية

توفر فئة std::string مجموعة من الدوال للبحث عن سلاسل فرعية (substrings) أو أحرف معينة داخل سلسلة نصية. تشمل هذه الدوال:

  • find(): تبحث عن أول ظهور لسلسلة فرعية أو حرف.
  • rfind(): تبحث عن آخر ظهور لسلسلة فرعية أو حرف.
  • find_first_of(): تبحث عن أول ظهور لأي من الأحرف المحددة.
  • find_last_of(): تبحث عن آخر ظهور لأي من الأحرف المحددة.
  • find_first_not_of(): تبحث عن أول حرف ليس من الأحرف المحددة.
  • find_last_not_of(): تبحث عن آخر حرف ليس من الأحرف المحددة.

أمثلة:


#include <iostream>
#include <string>

int main() {
  std::string str = "This is a test string";

  // البحث عن سلسلة فرعية
  size_t found = str.find("test");
  if (found != std::string::npos) {
    std::cout << "Found 'test' at: " << found << std::endl; // Found 'test' at: 10
  }

  // البحث عن آخر ظهور لحرف
  found = str.rfind('s');
  if (found != std::string::npos) {
    std::cout << "Last 's' at: " << found << std::endl; // Last 's' at: 20
  }

  // البحث عن أول ظهور لأي من الأحرف المحددة
  found = str.find_first_of("aeiou");
  if (found != std::string::npos) {
    std::cout << "First vowel at: " << found << std::endl; // First vowel at: 2
  }

  return 0;
}

تحويل السلاسل النصية

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

  • stoi(): لتحويل سلسلة نصية إلى عدد صحيح (int).
  • stol(): لتحويل سلسلة نصية إلى عدد صحيح طويل (long).
  • stoll(): لتحويل سلسلة نصية إلى عدد صحيح طويل جدًا (long long).
  • stof(): لتحويل سلسلة نصية إلى عدد عشري (float).
  • stod(): لتحويل سلسلة نصية إلى عدد عشري مزدوج (double).
  • stold(): لتحويل سلسلة نصية إلى عدد عشري مزدوج طويل (long double).
  • to_string(): لتحويل قيمة رقمية إلى سلسلة نصية.

أمثلة:


#include <iostream>
#include <string>

int main() {
  std::string strNum = "123";
  std::string strFloat = "3.14";

  // تحويل إلى عدد صحيح
  int num = std::stoi(strNum);
  std::cout << "Integer: " << num << std::endl; // Integer: 123

  // تحويل إلى عدد عشري
  double floatNum = std::stod(strFloat);
  std::cout << "Float: " << floatNum << std::endl; // Float: 3.14

  // تحويل عدد إلى سلسلة
  std::string strFromInt = std::to_string(42);
  std::cout << "String from int: " << strFromInt << std::endl; // String from int: 42

  return 0;
}

استخدام السلاسل النصية مع الملفات

يمكن استخدام فئة std::string لقراءة وكتابة البيانات النصية من وإلى الملفات. يتم ذلك باستخدام فئات الإدخال والإخراج في مكتبة .

أمثلة:


#include <iostream>
#include <fstream>
#include <string>

int main() {
  // كتابة إلى ملف
  std::ofstream outputFile("output.txt");
  if (outputFile.is_open()) {
    std::string str = "Hello, file writing!";
    outputFile << str << std::endl;
    outputFile.close();
    std::cout << "Wrote to file." << std::endl;
  } else {
    std::cerr << "Unable to open file for writing." << std::endl;
  }

  // قراءة من ملف
  std::ifstream inputFile("output.txt");
  if (inputFile.is_open()) {
    std::string line;
    std::getline(inputFile, line); // قراءة سطر كامل من الملف
    inputFile.close();
    std::cout << "Read from file: " << line << std::endl;
  } else {
    std::cerr << "Unable to open file for reading." << std::endl;
  }

  return 0;
}

نصائح لتحسين كفاءة استخدام السلاسل النصية

لتحسين أداء البرنامج عند التعامل مع السلاسل النصية، ضع في اعتبارك النصائح التالية:

  • تجنب النسخ غير الضرورية: عند تمرير السلاسل النصية إلى الدوال، استخدم تمريرًا بالإشارة (pass by reference) أو تمريرًا بالإشارة الثابتة (pass by const reference) لتجنب النسخ غير الضروري للسلاسل النصية الكبيرة.
  • استخدام احتياطي الذاكرة المسبق: إذا كنت تعرف الحجم التقريبي للسلسلة النصية، استخدم الدالة reserve() لحجز مساحة مسبقًا لتجنب إعادة تخصيص الذاكرة المتكررة.
  • استخدام عمليات الإضافة بكفاءة: عند إضافة سلاسل نصية متعددة، استخدم append() أو عملية الجمع (+=) بكفاءة، وتجنب إنشاء سلاسل مؤقتة غير ضرورية.
  • التحقق من الحدود: تأكد دائمًا من التحقق من الحدود قبل الوصول إلى أحرف السلسلة باستخدام الفهرسة أو at() لتجنب الأخطاء.

أمثلة إضافية

فيما يلي بعض الأمثلة الإضافية لاستخدام السلاسل النصية في سي++:


#include <iostream>
#include <string>
#include <algorithm> // Required for std::transform

int main() {
  std::string str = "hello world";

  // تحويل إلى أحرف كبيرة
  std::transform(str.begin(), str.end(), str.begin(), ::toupper);
  std::cout << "Uppercase: " << str << std::endl; // Uppercase: HELLO WORLD

  // إزالة المسافات البيضاء من البداية والنهاية (Trim)
  // (هذه الدالة غير موجودة بشكل مباشر في std::string، لذا يلزم استخدام طريقة مخصصة)
  // المثال التالي يوضح كيفية تنفيذ ذلك (ببساطة):
  size_t start = str.find_first_not_of(" ");
  if (std::string::npos != start) {
    size_t end = str.find_last_not_of(" ");
    str = str.substr(start, end - start + 1);
  }
  std::cout << "Trimmed: " << str << std::endl; // Trimmed: HELLO WORLD

  // تقسيم سلسلة نصية إلى أجزاء (Tokenization)
  std::string text = "apple,banana,orange";
  std::string delimiter = ",";
  size_t pos = 0;
  std::string token;
  while ((pos = text.find(delimiter)) != std::string::npos) {
    token = text.substr(0, pos);
    std::cout << "Token: " << token << std::endl;
    text.erase(0, pos + delimiter.length());
  }
  std::cout << "Last token: " << text << std::endl; // Last token: orange

  return 0;
}

3. خاتمة

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

4. المراجع

“`