alphabet_lower = "abcdefghijklmnopqrstuvwxyz"
alphabet_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"مسألة التشفير
في هذا التمرين تبني شيفرة قيصر خطوة بخطوة: إزاحة الحروف الإنجليزية مع التفاف حول الأبجدية، ثم تعمية نص كامل والتحقق من صحته. أكمل الدوال في الخلايا البرمجية حيث وردت تعريفاتها دون تنفيذ كامل.
التعمية أو التشفير المُلغَّز أو الإلغاز (بالإنجليزية: Cryptography) هو فرع من علم التعمية يهتم بممارسة بعض التقنيات لتأمين عملية التواصل بوجود أشخاص أخرين والذين يسمون أعداء (adversaries). بصورة عامة، تهتم التعمية بإنشاء الأنظمة التي تمنع الأعداء أو العامة من قراءة الرسائل الخاصة. أي بوسائل تحويل البيانات (مثل الكتابة) من شكلها الطبيعي المفهوم لأي شخص إلى شكل غير مفهوم بحيث يتعذّر على من لا يملك معرفة سرية محددة معرفة فحواها.
كان غايوس يوليوس قيصر (44 ق.م) يواجه خطر تسرب المعلومات في رسائله العسكرية في حال وقعت رسائله في أيدي العدو، فابتكر وسيلة بسيطة لإخفاء مضمونها: كان يُبدل كل حرف في النص بحرف آخر يليه بعدد معين من الخانات هذه الطريقة أصبحت تُعرف اليوم بـ شيفرة قيصر (Caesar Cipher).
فإذا كان مقدار الإزاحة 3 مثلاً يصير:
- حرف
aيصيرd - حرف
bيصيرe - حرف
cيصيرf
وأما الحروف الأخيرة فتدور، فيكون:
- حرف
xيصيرa - حرف
yيصيرb - حرف
zيصيرc
ومهمتك تطبيقها بخوارزمية تأخذ نصًّا وتعميه.
في الخلية التالية تعريف جاهز لسلسلتي الأحرف؛ شغّله ثم تابع الشرح:
تذكر أن لدينا في بايثون الفعل: str.index(sub: str) -> int حيث يأخذ هذا الفعل جُزءًا نصيًّا ويأتي على النص من أوله إلى آخر باحثًا عن موضعه. ونحن سنستعمل ذلك في البحث عن موضع الحرف فسيكون على النحو التالي:
print(alphabet_lower.index('a'))
print(alphabet_lower.index('z'))والأمر الآخر الذي سيفيدنا في تدوير الأرقام هو:
الحسابيات المقاسية (Modular Arithmetic) تتحرك فيه الأرقام بالجمع والضرب ونحوه بحيث تلتف الأرقام حول بعضها البعض عند الوصول إلى قيمة معينة، تسمى القياس (Modulus).
وهذه العملية في بايثون هي % وتعبر عن باقي القسمة:
(9 + 4) % 12أكمل الدالة encode التي تأخذ حرفًا (char) ومقدار الإزاحة (shift) وتعيد الحرف البديل بعد الإزاحة (مع التفاف حول الأبجدية).
def encode(char: str, shift: int) -> str:
"""
Returns the Caesar cipher encoding of the character `char` shifted by `shift`.
- If `char` is a lowercase or uppercase English letter, returns its shifted version (wrapping around the alphabet).
- Otherwise, returns the character unchanged.
"""- أولاً نبحث عن الحرف في سلسلة الأحرف الصغيرة، ثم الكبيرة، ثم إن لم يوجد في أي منها فإننا نعيد الحرف كما هو، ولا نزيحه
- فإن وجدنا الحرف في إحدى السلسلتين (الكبيرة أو الصغيرة) فإننا نعين المتغير
alphabetلهذه السلسلة التي سيتم البحث فيها بعد ذلك - نبحث في هذه السلسلة بالفعل
.index()لنعرف موضِع الحرف، حيث سيكون هذا هو رمزه الرقمي (code). - نزيح الرقم بالمقدار المعطى (
shift) ونُدير الناتج بعملية باقي القسمة وهي التعبير: (% len(alphabet)) - نعين المتغير
new_charللحرف الذي في موضع الرقم بعد الإزاحة - نعيد الحرف البديل
نختبر الدالة ببعض التوكيادت:
print(encode('a', 3) == 'd')
print(encode('b', 3) == 'e')
print(encode('x', 3) == 'a')
print(encode('y', 3) == 'b')دالة decode تعكس التعمية: تزيح الحرف في الاتجاه المعاكس (ما يعادل طرح الإزاحة مع التفاف).
def decode(char: str, shift: int) -> str:
"""
Returns the Caesar cipher decoding of the character `char` shifted by `shift`.
- If `char` is a lowercase or uppercase English letter, decodes by reversing the shift (wrapping around the alphabet).
- Otherwise, returns the character unchanged.
"""للتأكد من أن decode يعكس encode على مستوى الحرف، جرّب التوكيدات التالية (تمرير ناتج التعمية إلى decode بنفس الإزاحة):
print(decode(encode('a', 3), 3) == 'a')
print(decode(encode('z', 3), 3) == 'z')بعد أن يعمل encode على مستوى الحرف، عمِّ النص كاملًا. في الخلية التالية مثال جاهز لـ encode_text يستدعي encode لكل حرف؛ اقرأه ثم نفّذه:
def encode_text(text: str, shift: int) -> str:
result = ""
for char in text:
result += encode(char, shift)
return result- نبدأ بنص فارغ:
result = "" - نأتي على الحروف حرفًا حرفًا كما في النص
textونستعمل فعل التعميةencodeلذلك النص، ونضيف الحرف العائد إلى النص الناتجresult
أما عكس التعمية فباستعمال decode بدلاً من encode بمثل ما تقدَّم:
def decode_text(text: str, shift: int) -> str:
"""
Decodes the given text using the Caesar cipher with the specified shift.
Iterates over each character in `text`, applying the Caesar cipher decoding (reverse shift)
to each letter using the `decode` function. Non-letter characters remain unchanged.
Args:
text (str): The input string to decode.
shift (int): The number of positions that each letter was originally shifted.
Returns:
str: The decoded text.
"""قارِن مخرجاتك مع موقع تفاعلي جاهز: cryptii.com — استخدم نفس النص ونفس الإزاحة وتأكد أن النتيجة تطابق ما يظهر في الموقع:
assert (
encode_text("If he had anything confidential to say, he wrote it in cipher, that is, by so changing the order of the letters of the alphabet, that not a word could be made out", 3) ==
"Li kh kdg dqbwklqj frqilghqwldo wr vdb, kh zurwh lw lq flskhu, wkdw lv, eb vr fkdqjlqj wkh rughu ri wkh ohwwhuv ri wkh doskdehw, wkdw qrw d zrug frxog eh pdgh rxw"
)print(encode_text("If he had anything confidential to say, he wrote it in cipher, that is, by so changing the order of the letters of the alphabet, that not a word could be made out", 3))print("Li kh kdg dqbwklqj frqilghqwldo wr vdb, kh zurwh lw lq flskhu, wkdw lv, eb vr fkdqjlqj wkh rughu ri wkh ohwwhuv ri wkh doskdehw, wkdw qrw d zrug frxog eh pdgh rxw")أخيرًا جرّب على فقرة كاملة بعد أن تمرّ الاختبارات أعلاه:
text = "If he had anything confidential to say, he wrote it in cipher, that is, by so changing the order of the letters of the alphabet, that not a word could be made out."
print("## Text")
print(text)
text_encoded = encode_text(text, 3)
text_decoded = decode_text(text_encoded, 3)
print("## Encoded")
print(text_encoded)
print("## Decoded")
print(text_decoded)
