السابقالفهرسالتالي

الفصل 8

السلاسل المحرفية

 

8.1 استدعاء العمليات على الكائنات

في Java وغيرها من لغات البرمجة كائنية التوجه، توجد الكائنات، وهي مجموعات من البيانات المرتبطة ببعضها والتي ترفق بمجموعة من العمليات. تعمل هذه العمليات على الكائنات، تجري الحسابات وأحياناً تعدل بيانات الكائن.

من بين الأنواع التي شاهدناها حتى الآن، كانت السلاسل المحرفية (Strings) هي الكائنات الوحيدة. اعتماداً على تعريف الكائن، قد تتساءل "ما هي البيانات الموجودة في الكائن من نوع String؟" و "ما هي العمليات التي يمكننا استدعاؤها على كائن String؟"

البيانات المحتواة في كائن String هي حروف السلسلة المحرفية، أو –بصورة عامة أكثر– محارفها. هناك عدة عمليات قليلة تعمل على السلاسل المحرفية، لكنني لن استخدم سوى بضعة عمليات منها فقط في هذا الكتاب. بقية العمليات موثقة على http://download.oracle.com/javase/6/docs/api/java/lang/String.html.

أول عملية سنتعرف عليها هي charAt، التي تسمح لك باستخراج الحروف من السلسلة المحرفية. ولتخزين النتيجة، نحتاج إلى نوع متغيرات يمكنه تخزين الحروف المفردة. الحروف المفردة تدعى المحارف (characters)، ونوع المتغيرات الذي يخزنهم يدعى char.

تعمل المتغيرات من نوع char مثل بقية المتغيرات التي تعاملنا معها سابقاً:

char fred = ’c’;
if (fred == ’c’) {
  System.out.println (fred);
}
تظهر قيم المحارف بين علامتي تنصيص مفردة ('c'). بعكس القيم من نوع string (التي تظهر بين علامتي تنصيص مزدوجة)، القيم المحرفية يمكن أن تحتوي على حرف واحد فقط أو رمز.

هنا شرح طريقة استعمال عملية charAt:

String fruit = "banana";
char letter = fruit.charAt(1);
System.out.println (letter);
تشير التركيبة fruit.charAt إلى أنني أستدعي العملية charAt على الكائن fruit. مررت المتحول 1 إلى هذه العملية، ما يشير إلى أنني أود معرفة المحرف الأول من السلسلة. النتيجة هي قيمة من نوع char، يتم تخزينها في المتغير letter. عندما أطبع قيمة المتغير letter، أحصل على مفاجأة:
a
a ليس الحرف الأول من كلمة "banana". إلا إذا كنت عالماً بالكمبيوتر. تطبيقاً لمبدأ "خالِفْ تُعرَف"، يبدأ علماء الكمبيوتر العد من الصفر دائماً. الحرف الصفري (0th - "zeroeth letter") من كلمة "banana" هو b. أما الحرف الأول (1th - "oneth") هو a والحرف الثاني (2th - "twooth") هو n.

إذا أردت الحرف رقم 0 من سلسلة، عليك تمرير الصفر كمتحول:

char letter = fruit.charAt(0);

8.2 Length

العملية الثانية من عمليات String التي سنتعرف عليها هي العملية length، التي تعيد عدد المحارف الموجودة في سلسلة محرفية. مثلاً:

int length = fruit.length();
لا تأخذ length أية متحولات، وهو ما نشير إليه ب ()، وتعيد عدداً صحيحاً، في هذه الحالة 6. لاحظ أنه من المسموح وجود متغير وعملية لهما نفس اسم (على الرغم من أن هذا قد يشوش القراء البشر).

لمعرفة الحرف الأخير من سلسلة، قد تحاول كتابة شيء مثل هذا

int length = fruit.length();
char last = fruit.charAt (length); 		// WRONG!!
ذلك لن يعمل. السبب هو عدم وجود حرف سادس في كلمة "banana". نظراً لأننا بدأنا العد من الصفر، فإن الحروف الستة مرقمة من 0 إلى 5. للحصول على المحرف الأخير، عليك طرح واحد من length.
int length = fruit.length();
char last = fruit.charAt (length-1);

8.3 الاجتياز

من الأشياء الشائع فعلها بالسلاسل هو البدء عند المحرف الأول، اختيار كل محرف بدوره، إجراء عملية ما عليه، والمتابعة حتى نهاية السلسلة. هذا النموذج من المعالجة يدعى الاجتياز (أو العبور traversal). إحدى الطرق الطبيعية المستخدمة لترميز الاجتياز (أو تشفيره - بمعنى كتابته بالشفرة البرمجية) تتم باستخدام تعليمة while:

int index = 0;
while (index < fruit.length()) {
  char letter = fruit.charAt (index);
  System.out.println (letter);
  index = index + 1;
}
هذه الحلقة تعبر السلسلة المحرفية وتطبع كل حرف على سطر لوحده. لاحظ أن الشرط هو index < fruit.length()، ما يعني أن الشرط لن يتحقق عندما يكون index مساوياً لطول السلسلة المحرفية، ولن يتم تنفيذ جسم الحلقة. آخر محرف سوف نعالجه هو المحرف ذا الدليل fruit.length()-1.

اسم متغير الحلقة هو index. الدليل (index) هو متغير أو قيمة تستخدم لتحديد عنصر ما من مجموعة مرتبة (في هذه الحالة مجموعة المحارف في السلسلة المحرفية). الدليل يشير إلى (أو يدل على – بحسب اسمه) العنصر الذي تريده. يجب أن تكون المجموعة مرتبة حتى يكون لكل حرف دليل وكل دليل يشير إلى محرف واحد فقط.

تمرين 8.1

اكتب عملية تأخذ سلسلة محرفية كمتحول وتطبع الأحرف بالمقلوب (من الأخير إلى الأول)، على سطر واحد.

8.4 أخطاء وقت التشغيل

بعيداً جداً في القسم 1.3.1، تحدثت عن أخطاء التشغيل (run-time errors)، وهي أخطاء لا تظهر قبل بدء البرنامج بالعمل. تدعى أخطاء التشغيل في Java بالاستثناءات (exceptions).

الأغلب أنك لم تر العديد من أخطاء التشغيل حتى الآن، لأننا لم نفعل أي أشياء تؤدي إلى ذلك. حسن، الآن نحن نفعل ذلك. إذا استخدمت أمر charAt وأعطيته دليلاً سالباً أو أكبر من length-1، فستحصل على استثناء: بشكل محدد، ستحصل على StringIndexOutOfBoundsExeption. جرب وانظر كيف سيبدو.

إذا تسبب برنامجك باستثناء، سيطبع رسالة خطأ تبين نوع الاستثناء بالإضافة إلى سجل المكدس (stack trace)، الذي يبين العملية التي كانت تجري وقت حدوث الاستثناء. إليك مثالاً:

public class BadString {
   public static void main(String[] args) {
      processWord("banana");
   }

   public static void processWord(String s) {
      char c = getLastLetter(s);
      System.out.println(c);
   }

   public static char getLastLetter(String s) {
      int index = s.length(); 		// WRONG!
      char c = s.charAt(index);
      return c;
   }
}
لاحظ الخطأ في getLastLetter: يجب أن يكون دليل آخر حرف s.length()-1. إليك ما ستحصل عليه:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: 6
	at java.lang.String.charAt(String.java:694)
	at BadString.getLastLetter(BadString.java:24)
	at BadString.processWord(BadString.java:18)
	at BadString.main(BadString.java:14)
بعدها ينتهي البرنامج. قد تكون قراءة سجل المكدس صعبة، لكنه يحتوي على الكثير من المعلومات.

تمرين 8.2

اقرأ سجل المكدس وأجب عن الأسئلة التالية:

8.5 قراءة الوثائق

إذا ذهبت إلى http://download.oracle.com/javase/6/docs/api/java/lang/String.html ونقرت على charAt، ستحصل على التوثيق التالي (أو شيء يشبهه):

public char charAt(int index)

Returns the char value at the specified index. An index ranges from 0 to length( ) - 1. The first char value of the sequence is at index 0, the next at index 1, and so on, as for array indexing.

Parameters: index - the index of the char value.

Returns: the char value at the specified index of this string. The first char value is at index 0.

Throws: IndexOutOfBoundsException - if the index argument is negative or not less than the length of this string.

السطر الأول هو نموذج العملية الأولي (prototype)، الذي يبين اسم العملية، نوع معاملاتها، ونوع الإرجاع.

السطر التالي يصف وظيفة العملية. السطر الذي يليه يشرح المعاملات والقيم المعادة. كانت الشروحات مطولة في هذه الحالة، لكن الواجب أن يوافق التوثيق صيغة قياسية. السطر الأخير يشرح أية استثناءات، في حال وجود بعضها، يمكن أن تطلقها هذه العملية.

قد تحتاج لبعض الوقتت حتى تعتاد على هذا النوع من الوثائق، لكنها تستحق الجهد المبذول.

8.6 عملية indexOf

عملية indexOf هي نقيض العملية charAt. تأخذ charAt دليلاً وتعيد المحرف الموجود عند ذلك الدليل. أما indexOf فتأخذ محرفاً وتبحث عن الدليل الذي يظهر ذلك المحرف عنده.

تفشل charAt إذا كان الدليل يخرج عن نطاق السلسلة المحرفية، وتتسبب في استثناء. تفشل indexOf إذا لم يظهر المحرف في السلسلة أبداً، وتعيد القيمة 1-.

String fruit = "banana";
int index = fruit.indexOf(’a’);
هذا المثال يبحث عن دليل الحرف 'a' في السلسلة. في هذه الحالة، يظهر الحرف ثلاثة مرات، لذا لن يكون واضحاً ما يجب أن تفعله indexOf هنا. وفقاً للوثائق، فإنها ستعيد دليل الظهور الأول للحرف.

لإيجاد أدلة التكرارات التالية، توجد نسخة بديلة من indexOf (لشرح هذا النوع من التحميل الزائد، انظر القسم 6.4). تأخذ تلك النسخة متحولاً ثانياً يشير إلى الموقع من السلسلة الذي يجب بدء البحث منه. إذا استدعينا

int index = fruit.indexOf(’a’, 2);
فستبدأ البحث عند الحرف الثاني (حرف n الأول) وستجد حرف a الثاني، الموجود عند الدليل 3. إذا تصادف وجود الحرف عند دليل البدء، يكون دليل البدء هو الجواب. وهكذا،
int index = fruit.indexOf(’a’, 5);
ستعيد 5.

8.7 الحلقات والعد

يعد البرنامج التالي مرات ظهور الحرف 'a' في السلسلة:

String fruit = "banana";
int length = fruit.length();
int count = 0;
int index = 0;
while (index < length) {
  if (fruit.charAt(index) == ’a’) {
    count = count + 1;
  }
  index = index + 1;
}
System.out.println (count);
هذا البرنامج يشرح مفهوماً شائعاً، يدعى العداد (counter). تتم تهيئة المتغير count بالقيمة صفر، ثم نزيده بمقدار واحد في كل مرة نجد فيها 'a' (في اللغة الإنكليزية يعبر الفعل increment لوحده عن الزيادة بمقدار واحد؛ وهو عكس الفعل decrement، ولا علاقة لهما بالاسم excrement). عندما نخرج من الحلقة، يحتوي count على النتيجة: المجموع النهائي لعدد حروف 'a' الموجودة.

تمرين 8.3

قم بتغليف هذه الشفرة في عملية باسم countLetters، وقم بتعميمها بحيث تقبل السلسلة والمحرف كمتحولين.

ثم أعد كتابة العملية بحيث تستخدم indexOf لتحديد مواقع حروف 'a'، بدلاً من التحقق من المحارف واحداً تلو الآخر.

8.8 عوامل الزيادة والإنقاص بمقدار واحد

إن الزيادة أو الطرح بمقدار واحد هي عمليات شائعة جداً لدرجة أن Java توفر عوامل خاصة لها. يضيف العامل (++) واحد إلى القيمة الحالية لمتغير من نوع int أو char. والعامل (--) يطرح واحد منها. لا تعمل أي من العمليتين على المتغيرات من نوع double أو boolean أو String.

تقنياً، من المشروع زيادة متغير بمقدار واحد واستعماله في عبارة ما في نفس الوقت. مثلاً، قد ترى شيئاً مثل هذا:

System.out.println (i++);
بالنظر إلى هذا، لن يكون واضحاً ما إذا كانت الزيادة ستتم قبل طباعة القيمة أو بعدها. وبما أن العبارات المشابهة لهذه تميل للعصيان على الفهم، سأحاول منعك من استخدامها. في الواقع، لأثبط همتك أكثر، لن أقول لك النتيجة. إذا أردت أن تعرف حقاً، يمكنك تجربتها.

يمكننا إعادة كتابة عداد الحروف، باستخدام عوامل الزيادة بمقدار واحد:

int index = 0;
while (index < length) {
  if (fruit.charAt(index) == ’a’) {
    count++;
  }
  index++;
}
من الأخطاء الشائعة كتابة شيء مثل
index = index++; 	// WRONG!!
لسوء الحظ، هذه العبارة صحيحة لغوياً، لذا فإن المترجم لن يحذرك. إن تأثير هذه التعليمة هو ترك قيمة index بدون تغيير. هذه الغلطة غالباً ما تكون صعبة الاكتشاف.

تذكر، يمكنك كتابة index = index+1; أو كتابة index++; لكن لا يمكنك خلطهما معاً.

8.9 السلاسل المحرفية غير قابلة للتغيير

عندما تنظر إلى توثيق عمليات السلاسل المحرفية، قد تلاحظ العمليتين toUpperCase وtoLowerCase. غالباً ما تكون هاتان العمليتان مصدراً للحيرة، لأنك قد تشعر أنهما ستغيران السلسلة المعطاة. في الحقيقة، ولا واحدة من هاتين العمليتين أو أي عملية أخرى يمكن لها أن تغير سلسلة محرفية، لأن السلاسل المحرفية غير قابلة للتعديل (immutable).

عندما تستدعي toUpperCase على سلسلة ما، ستحصل على سلسلة جديدة كقيمة معادة. مثلاً:

String name = "Alan Turing";
String upperName = name.toUpperCase ();
بعد تنفيذ السطر الثاني، ستحتوي السلسلة upperName على القيمة "ALAN TURING"، في حين أن السلسلة name ستحافظ على قيمتها "Alan Turing".

8.10 السلاسل المحرفية غير قابلة للمقارنة

من الضروري في كثير من الأحيان أن نقارن بين سلسلتين لنرى إذا كانتا متطابقتين أو لنرى أي واحدة تسبق الأخرى حسب الترتيب الأبجدي. سيكون لطيفاً لو أمكننا استخدام عوامل المقارنة، مثل == و <، لكن ذلك غير ممكن.

حتى نقارن بين سلسلتين، علينا استخدام عمليتي equals وcompareTo. مثلاً:

String name1 = "Alan Turing";
String name2 = "Ada Lovelace";
if (name1.equals (name2)) {
   System.out.println ("The names are the same.");
}
int flag = name1.compareTo (name2);
if (flag == 0) {
   System.out.println ("The names are the same.");
} else if (flag < 0) {
   System.out.println ("name1 comes before name2.");
} else if (flag > 0) {
   System.out.println ("name2 comes before name1.");
}
تبدو بنية التعليمات غريبة قليلاً هنا. للمقارنة بين شيئين، عليك استدعاء عملية على أحدهما وتمرير الآخر كمتحول.

القيمة المعادة من equals واضحة بشكل كاف؛ true إذا احتوت السلسلتين على نفس المحارف، وfalse ما عدا ذلك.

القيمة المعادة من compareTo غريبة قليلاً. إن الفرق بين المحارف الأولى في السلسلتين هو الذي يختلف. إذا كانت السلسلتان متساويتين، يكون الفرق 0. إذا كانت السلسلة الأولى (التي تم استدعاء العملية عليها) تسبق الثانية في الأبجدية، يكون الفرق سالباً. وإلا، فسيكون الفرق موجباً. في هذه الحالة سيكون الفرق 8 موجب، لأن الحرف الثاني من "Ada" يأتي قبل الحرف الثاني من "Alan" بثمانية حروف.

ولنبلغ حد الكمال، علينا أن نعترف بأن استخدام عامل == مع السلاسل المحرفية مشروع، إلا أنه نادراً ما يكون صحيحاً. سأشرح السبب في القسم 13.4؛ أما الآن، فلا تستخدمه.

8.11 المصطلحات

كائن: مجموعة من البيانات المترابطة التي ترفق بمجموعة من العمليات التي تشتغل عليها. كانت الكائنات التي استخدمناها حتى الآن هي String، Bug، Rock، وبقية كائنات GridWorld.

دليل: متغير أو قيمة تستخدم لاختيار أحد عناصر مجموعة مرتبة، مثل محرف من سلسلة محرفية.

الاستثناء: خطأ تشغيل.

إطلاق الاستثناء: التسبب بحدوثه.

سجل المكدس: تقرير يظهر حالة البرنامج عند حدوث استثناء.

نموذج أولي: السطر الأول من العملية، الذي يعرف اسمها، ومعاملاتها، ونوع الإرجاع.

الاجتياز: هو المرور على جميع عناصر مجموعة وتنفيذ إجراء مشابه على كل منها.

عداد: متغير يستخدم لعد شيء ما، عادة يتم تهيئته بالصفر ثم تتم زيادته.

الزيادة بمقدار واحد: زيادة قيمة المتغير بقدار واحد. عامل الزيادة في Java هو ++.

الإنقاص بمقدار واحد: طرح واحد من قيمة المتغير. عامل الإنقاص بمقدار واحد في Java هو --.

object: A collection of related data that comes with a set of methods that operate on it. The only objects we have used so far are Strings.

index: A variable or value used to select one of the members of an ordered set, like a character from a string.

exception: A run-time error.

throw: Cause an exception.

stack trace: A report that shows the state of a program when an exception occurs.

prototype: The first line of a method, which specifies the name, parameters and return type.

traverse: To iterate through all the elements of a set performing a similar operation on each.

counter: A variable used to count something, usually initialized to zero and then incremented.

increment: Increase the value of a variable by one. The increment operator in Java is ++.

decrement: Decrease the value of a variable by one. The decrement operator in Java is --.

8.12 تمرينات

تمرين 8.4

الغرض من هذا التمرين هو مراجعة التغليف والتعميم.

  1. غلف كسرة الشفرة التالية، لتحويلها إلى عملية تأخذ سلسلة محرفية كمعامل وتعيد قيمة count النهائية.
  2. في جملة واحدة أو اثنتين، اشرح ما تفعله العملية الناتجة بصورة مجردة (بدون الدخول في تفاصيل كيفية العمل).
  3. بفرض أنك عممت هذه العملية بحيث تعمل على أية سلسلة محرفية، ماذا يمكنك أن تفعل لتعميمها أكثر؟
    String s = "((3 + 7) * 2)";
    int len = s.length ();
    int i = 0;
    int count = 0;
      while (i < len) {
        char c = s.charAt(i);
        if (c == ’(’) {
          count = count + 1;
        } else if (c == ’)’) {
          count = count - 1;
        }
        i = i + 1;
      }
    System.out.println (count);
    

تمرين 8.5

الغرض من هذا التمرين هو استكشاف أنواع المتغيرات في Java وتغطية بعض التفاصيل التي لم يغطها هذا الفصل.

  1. أنشئ برنامجاً جديداً باسم Test.java واكتب عملية main تحتوي على عدة عبارات تجمع بين أنواع مختلفة باستخدام عامل +. مثلاً، ماذا يحدث إذا "جمعت" String مع char؟ هل يتم تنفيذ عملية الجمع أم ربط السلاسل؟ ما هو نوع النتيجة؟ (كيف يمكنك تحديد نوع النتيجة؟)
  2. اصنع نسخة مكبرة من الجدول التالي واملأها. عند تقاطع كل زوج من الأنواع، عليك أن تبين ما إذا كان استخدام عامل (+) مشروعاً مع هذه الأنواع، ما هي العملية التي سينفذها (جمع أو ربط)، وما هو نوع النتيجة.

     

    String

    int

    char

    boolean

    boolean

     

     

     

     

    char

     

     

     

     

    int

     

     

     

     

    String

     

     

     

     

  3. فكر ببعض القرارات التي اتخذها مصممو لغة Java عندما ملؤوا هذا الجدول. كم عنصراً يبدو معقولاً، بحيث لا توجد أية خيارات معقولة أخرى؟ كم واحداً يبدو اختياراً عشوائياً من بين عدة احتمالات معقولة؟ كم واحداً من هذه العناصر يبدو غبياً؟
  4. إليك حزورة: عادة، تعليمة x++ مطابقة تماماً لتعليمة x = x + 1. إلا إذا كان x من نوع char ! في تلك الحالة، x++ مشروعة، لكن x = x + 1 تسبب خطأ. جربها وانظر إلى رسالة الخطأ التي ستحصل عليها، ثم حاول أن تعرف ماذا يجري.

تمرين 8.6

ما هو خرج هذا البرنامج؟ صِف، في جملة واحدة ما تفعله العملية bing (ليس كيفية عملها).

public static String bing (String s) {
  int i = s.length() - 1;
  String total = "";
  while (i >= 0 ) {
    char ch = s.charAt (i);
    System.out.println (i + " " + ch);
    total = total + ch;
    i--;
  }
    return total;
  }
  public static void main (String[] args) {
    System.out.println (bing ("Allen"));
  }
}

تمرين 8.7

أعطاك أحد أصدقاءك العملية التالية ويقول أنه إذا كان المتغير number يحتوي على أية عدد مؤلف من خانتين، فإن البرنامج سيطبع الرقم بالمقلوب. هو يدعي أنه في حال كانت قيمة number تساوي 17، ستطبع العملية 71.

هل هو محق؟ إذا لم يكن كذلك، اشرح ما يفعله البرنامج فعلاً وقم بتعديله لينفذ الإجراء الصحيح.

int number = 17;
int lastDigit = number%10;
int firstDigit = number/10;
System.out.println (lastDigit + firstDigit);

تمرين 8.8

ما هو خرج هذا البرنامج؟

public class Enigma {

  public static void enigma(int x) {
    if (x == 0) {
      return;
    } else {
      enigma(x/2);
    }
    System.out.print (x%2);
  }
  public static void main (String[] args) {
    enigma(5);
    System.out.println ("");
  }
}
اشرح في 4-5 كلمات ما تفعله العملية enigma فعلاً.

تمرين 8.9

  1. أنشئ برنامجاً جديداً باسم Palindrome.java.

  2. اكتب عملية باسم first تأخذ سلسلة محرفية وتعيد الحرف الأول، وأخرى باسم last تعيد الحرف الأخير.
  3. اكتب عملية باسم middle تأخذ سلسلة محرفية وتعيد سلسلة فرعية تحتوي كل شيء عدا الحرفين الأول والأخير.

    مساعدة: اقرأ توثيق العملية substring الموجودة في صنف String. قم ببعض الاختبارات لتتأكد أنك تفهم آلية عمل substring قبل أن تحاول كتابة middle.

    ماذا يحدث لو استدعيت middle على سلسلة مؤلفة من حرفين فقط؟ حرف واحد؟ أو سلسلة لا تحوي أية حروف؟

  4. إن التعريف المعتاد للكلمة المتناظرة (palindrome) هو كلمة يمكن قراءتها بشكل صحيح بكلا الاتجاهين، مثل "deed" و "level". لتعريف صفة مثل هذه بطريقة مختلفة يجب تحديد طريقة لاختبار وجود الصفة. مثلاً، يمكننا القول أن "الحرف المفرد هو كلمة متناظرة، وأن أي كلمة مؤلفة من حرفين تكون متناظرة إذا كان الحرفين متطابقين، وأن أي كلمة أخرى تكون متناظرة في حال تطابق الحرفين الأول والأخير وكان وسط الكلمة متناظراً أيضاً".

    اكتب عملية تعاودية اسمها isPalindrome تأخذ سلسلة محرفية وتعيد قيمة بوليانية تبين فيما لو الكلمة متناظرة أو لا.

  5. بعد أن يعمل فاحص الكلمات المتناظرة الذي كتبته، ابحث عن طرق لتبسيطه من خلال تخفيض عدد الشروط التي يتحقق منها. مساعدة: قد يكون من المفيد تبني فكرة أن السلسلة الفارغة تعتبر كلمة متناظرة.
  6. على ورقة، قم بابتكار استراتيجية للتحقق من تناظر الكلمات باستخدام التكرار. توجد عدة أساليب ممكنة، لذا تأكد من امتلاك خطة محكمة قبل البدء بكتابة الشفرة.
  7. نفذ استراتيجيتك في عملية باسم isPalindromeIter.
  8. اختياري: يوجد في الملحق B شفرة تقرأ قائمة كلمات من ملف. اقرأ قائمة كلمات واطبع المتناظرة منها.

تمرين 8.10

يقال عن كلمة أنها "أبجدية - abecedarian" إذا كانت حروف الكلمة تظهر وفق الترتيب الأبجدي. مثلاً، كافة الكلمات التالية هي كلمات إنكليزية أبجدية مؤلفة من 6 حروف.

abdest, acknow, acorsy, adempt, adipsy, agnosy, befist, behint,
beknow, bijoux, biopsy, cestuy, chintz, deflux, dehors, dehort,
deinos, diluvy, dimpsy
  1. صف خوارزمية للتحقق من كلمة معطاة (سلسلة محرفية) فيما إذا كانت أبجدية أو لا، بفرض أن الكلمة مكتوبة بالأحرف الصغيرة فقط. يمكن لخوارزميتك أن تكون تكرارية أوتعاودية.
  2. نفذ خوارزميتك في عملية اسمها isAbecedarian.

تمرين 8.11

dupledrome هي كلمة تحتوي على أحرف مضاعفة فقط، مثل "llaammaa" أو "ssaabb". أنا أظن بأنه لا توجد أي dupledromes في اللغة الإنكليزية المعتادة. لاختبار ذلك التخمين، أنا أرغب ببرنامج يقرأ الكلمات من القاموس واحدة تلو لأخرى ويفحصها للتحقق من كونها dupledrome أو لا.

اكتب عملية باسم isDupledrome تأخذ سلسلة محرفية وتعيد قيمة بوليانية تبين فيما إذا كانت الكلمة dupledrome أو لا.

تمرين 8.12

  1. تعمل حلقة فك شفرة الكابتن كرنش (Captain Crunch) بأخذ كل حرف في سلسلة محرفية وإضافة 13 إليه. مثلاً، 'a' سيصبح 'n' و'b' سيصبح 'o'. ستلتف الحروف عندما تصل للنهاية، لذا فإن 'z' سيصبح 'm'.

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

  2. عمم عملية كابتن كرنش حتى تضيف كمية معطاة إلى الحروف بدلاً من الرقم 13. الآن يجب أن تكون قادراً على تشفير الأشياء بإضافة 13 وفك التشفير بإضافة 13-. جربها.

تمرين 8.13

إذا حللت تمارين GridWorld من الفصل 5، فقد تستمتع بهذا التمرين. الهدف هو استخدام قوانين المثلثات لجعل الحشرات تلاحق بعضها.

اصنع نسخة من BugRunner.java باسم ChaseRunner.java واستوردها إلى بيئة البرمجة عندك. قبل عمل أي شيء، تأكد أنك قادر على تجميعه وتشغيله.

السابقالفهرسالتالي