نظرة عامة على السلاسل النصية في سي++
في سي++، يتم تمثيل السلاسل النصية باستخدام فئة 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. المراجع
- cppreference.com – std::basic_string
- GeeksforGeeks – String class in C++
- TutorialsPoint – C++ Strings
- LearnCpp.com – Strings Introduction
“`