النصوص وإنشاؤها
حتى الآن طبعنا جملًا جاهزة وخزّنا أرقامًا — لكن أغلب ما نتعامل معه في البرامج أسماء وكلمات وجمل. هذا الدرس يعلّمك النوع الذي يحملها كلها: String.
تخيّل النص سلسلة حروف معلّقة في خيط: "سارة" أو "أهلاً بالعالم". في جافا نكتب النص بين علامتي تنصيص مزدوجتين " "، ونخزّنه في متغير من نوع String — بحرف S كبير دائمًا.
ولأن البرامج نادرًا ما تكتفي بنص واحد، توفّر جافا عملية الالتصاق +: نضع نصًا بجانب نص أو نصًا بجانب رقم فتُلصق القيم ببعضها في نص جديد.
public class StringsIntro { public static void main(String[] args) { String name = "سارة"; String greeting = "مرحبًا يا "; System.out.println(greeting + name); System.out.println("علامة تنصيص داخل النص: \"جافا\""); System.out.println("نص + رقم: " + 2024); System.out.println("بدون أقواس: " + 2 + 3); System.out.println("مع أقواس: " + (2 + 3)); System.out.println("الطول: " + name.length()); System.out.println("النص الفارغ طوله: " + "".length()); }}
اقرأ المثال سطرًا سطرًا
- String name = "سارة"; ينشئ متغير نصيًا ويخزّن فيه السلسلة — النوع String والقيمة بين مزدوجتين.
- greeting + name تلصق النصين: «مرحبًا يا سارة».
- لإظهار علامة تنصيص داخل النص نسبقها بشرطة مائلة: \" — وإلا ظنّت جافا أن النص انتهى.
- "نص + رقم: " + 2024 يلصق الرقم كنص — أي رقم بجانب نص يتحول تلقائيًا إلى نص.
- name.length() تعيد عدد الحروف — تنبيه مهم: مع النصوص تُكتب length() بقوسين، خلافًا للمصفوفات التي تُكتب بلا قوسين.
- النص الفارغ "" نص مشروع تمامًا — طوله صفر، وسنبني عليه نصوصًا جديدة في الدرس الثالث.
توقّع الناتج قبل التالي
قراءة النص: الحروف والمقاطع والبحث
النص ليس كتلة واحدة — إنه شارع فيه بيوت مرقّمة. هذا الدرس يعطيك مفاتيح البيوت: charAt للوصول لحرف واحد، وindexOf للبحث عن موضع، وsubstring لقصّ مقطع كامل.
لكل حرف في النص فهرس (رقم موضع) يبدأ من 0 وليس من 1 — تمامًا كما بدأنا العد في المصفوفات. فنص "محمد" حرفه الأول charAt(0) وحرفه الأخير charAt(3)، أي length() - 1.
اكشف الإجابة
لأن الطول = النهاية − البداية = 3 − 0 = 3: تبدأ من الحدّ 0 وتتوقف عند الحدّ 3 دون أخذ الحرف الذي فهرسه 3، فتحصل على الفهارس 0 و1 و2 فقط (مثلًا من "Java" تحصل على "Jav").وللبحث عن مقطع داخل نص نستخدم indexOf: تعيد موضع أول ظهور، أو -1 إذا لم تجده — والرقم -1 هو إشارة «غير موجود» التي ستميّزها في كل برامجك.
public class ReadText { public static void main(String[] args) { String name = "محمد أحمد"; System.out.println("أول حرف: " + name.charAt(0)); System.out.println("آخر حرف: " + name.charAt(name.length() - 1)); int space = name.indexOf(" "); System.out.println("موضع المسافة: " + space); System.out.println("الاسم الأول: " + name.substring(0, space)); System.out.println("بعد المسافة: " + name.substring(space + 1)); System.out.println("هل يحتوي x؟ " + name.indexOf("x")); String a = "جافا"; String b = "جافا"; System.out.println("بالمحتوى equals: " + a.equals(b)); }}
اقرأ المثال سطرًا سطرًا
- charAt(0) يعيد الحرف الأول، وcharAt(length() - 1) يعيد الحرف الأخير — الفهرس الأخير دائمًا «الطول ناقص 1».
- indexOf(" ") وجدت المسافة عند الفهرس 4، وindexOf("x") لم تجدها فعادت بـ -1.
- substring(0, space) تقصّ من الفهرس 0 حتى ما قبل المسافة — المعامل الثاني غير مشمول في المقطع (يُستبعد).
- substring(space + 1) بمعامل واحد تقصّ من الموضع المحدد حتى نهاية النص — تعطي «أحمد».
- a.equals(b) تقارن المحتوى حرفًا حرفًا وعادت بـ true.
المقارنة المتساهلة مع حالة الأحرف
تخيّل طالبًا كتب إجابته "JAVa" بينما النموذج "java"! equals تقارن حرفًا حرفًا بحساسية كاملة لحالة الأحرف، أما equalsIgnoreCase فتتجاهل الفرق بين الكبيرة والصغيرة:
public class AnswerCheck { public static void main(String[] args) { String student = "JAVa"; System.out.println("بالمحتوى الدقيق: " + student.equals("java")); System.out.println("متجاهلة حالة الأحرف: " + student.equalsIgnoreCase("java")); }}
تغيير النصوص وبناؤها
هنا مفاجأة جافا الكبرى: النص لا يتغيّر أبدًا بعد إنشائه — كل «تعديل» يبني نصًا جديدًا. سنفهم هذه الفكرة ثم نستخدمها لنبني نصوص جديدة من مقاطع جاهزة.
تخيّل النص صخرة منقوشة لا تُمحى: عندما نكتب s.toUpperCase() لا تتغير الصخرة، بل يُنحت منها نسخة جديدة بحروف كبيرة ونعيدها لمتغير. لهذا السبب نكتب دائمًا String big = s.toUpperCase(); — نلتقط الناتج الجديد في متغير، ولو اكتفينا بكتابة s.toUpperCase(); وحده لضاع النص الجديد ولا أثر له على s.
ماذا تطبع println(s) الآن؟
وأجمل تطبيق على البناء هو توليد نصوص مركّبة من قطع: نلصق الاسم الأول والأخير بنقطة بينهما لنصنع «اسم مستخدم»، ثم نشتق منه صورته الصغيرة والكبيرة — كلها نصوص جديدة لا تمس الأصل.
public class BuildUser { public static void main(String[] args) { String first = "Sara"; String last = "Ali"; String user = first + "." + last; System.out.println("الاسم: " + first + " " + last); System.out.println("اسم المستخدم: " + user.toLowerCase()); System.out.println("الرمز: " + user.toUpperCase() + "-2026"); }}
اقرأ المثال سطرًا سطرًا
- first + "." + last تلصق القطع الثلاثة في نص واحد جديد: "Sara.Ali" — خزّنّاه في user.
- user.toLowerCase() تعيد نسخة جديدة كلها صغيرة: "sara.ali" — أما user نفسه فلم يتغير.
- user.toUpperCase() + "-2026" تجمع تحويلًا آخر مع لصق رقم — الناتج: "SARA.ALI-2026".
- القاعدة الذهبية: كل ميثود تعيد نصًا جديدًا؛ من أراد الناتج خزّنه في متغير أو اطبعه فورًا.
String s = "java"; s.toUpperCase(); System.out.println(s);
String s = "Ali"; String t = s.toUpperCase(); System.out.println(s + t);
تحدي: أين الخطأ؟
ثلاثة برامج عن النصوص — أخطاء النصوص لا توقف البرنامج دائمًا: بعضها يعطي نتيجة صامتة خاطئة! اقرأ الكود بتمعّن وتتبّع الناتج سطرًا سطرًا، ثم اضغط على السطر المخالف.
المقطع ١: برنامج ترحيب بسيط لا يعمل من الأساس. أين الخطأ؟
اقرأ رسالة الخطأ بتمعّن: ماذا قال عن علامتي التنصيص؟ وما نوع القيمة التي تُكتب بين مفردتين في جافا؟
المقطع ٢: نريد آخر حرف من النص لكن البرنامج يتوقف بخطأ. أين الخطأ؟
كم عدد الحروف في "جافا"؟ وما أكبر فهرس مشروع إذا بدأ العد من صفر؟ راجع فخ «الفهرس خارج النطاق» في الدرس 3·2.
المقطع ٣: نريد مجموع عددين لكن الناتج «المجموع: 23»! أين الخطأ؟
لا خطأ هنا — البرنامج يعمل تمامًا لكن ناتجه خاطئ. تتبّع التنفيذ من اليسار إلى اليمين: متى يتحول التعبير إلى نص؟
تمارين الوحدة ٣
تمارين على التعامل مع النصوص (الإنشاء والالتصاق، قراءة الحروف والمقاطع، وبناء نصوص جديدة بالمقاطع). كل تمرين أمامه كود ناقص: اضغط «✎ تعديل»، اكتب الكود المطلوب مكان التعليقات، اضغط «✔ حفظ» ثم «▶ تشغيل» — وقارن نتيجتك بالهدف المكتوب أسفل كل تمرين.
اسم الطالب مخزّن في المتغير name. أكمل سطرين: السطر الأول يطبع ترحيبًا بالاسم «مرحبًا بك يا ...»، والثاني يطبع عدد أحرف الاسم باستخدام length() بالصيغة «اسمك فيه ... أحرف».
public class Welcome { public static void main(String[] args) { String name = "سارة"; // ١) اطبع: مرحبًا بك يا (الاسم) // ٢) اطبع: اسمك فيه (الطول) أحرف }}
مرحبًا بك يا سارة اسمك فيه 4 أحرف
الاسم الأول في first والأخير في last. أكمل سطرًا واحدًا يعرّف المتغير full الذي يجمعهما بمسافة بينهما — تذكر أن المسافة نص منفصل تلتصقه بينهما.
public class FullName { public static void main(String[] args) { String first = "خالد"; String last = "العمري"; // عرّف full = first + مسافة + last System.out.println("الاسم الكامل: " + full); }}
الاسم الكامل: خالد العمري
الاسم الكامل "نورة سعد" مخزّن في full. أكمل المتغيرين الناقصين: space يخزّن موضع المسافة باستخدام indexOf، وfirst يخزّن الاسم الأول بقصّ النص من البداية حتى المسافة بـ substring.
public class FirstName { public static void main(String[] args) { String full = "نورة سعد"; // ١) موضع المسافة في متغير space (int) باستخدام indexOf // ٢) الاسم الأول في متغير first باستخدام substring System.out.println("الاسم الأول: " + first); }}
الاسم الأول: نورة