= "abcdefghijklmnopqrstuvwxyz"
alphabet_lower = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" alphabet_upper
التشفير
من أقدم أنواع تعمية النص (Text Encryption) شيفرة سيزر (Ceasar 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'))
0
25
والأمر الآخر الذي سيفيدنا في تدوير الأرقام هو:
الحسابيات المقاسية (Modular Arithmetic) تتحرك فيه الأرقام بالجمع والضرب ونحوه بحيث تلتف الأرقام حول بعضها البعض عند الوصول إلى قيمة معينة، تسمى القياس (Modulus).
وهذه العملية في بايثون هي %
وتعبر عن باقي القسمة:
9 + 4) % 12 (
1
والآن نعرف الدالة التي ستأخذ حرفًا (char
) ومقدار الإزاحة (shift
) لتعيد الحرف البديل عنه بعد الإزاحة.
def encode(char: str, shift: int) -> str:
if char in alphabet_lower:
= alphabet_lower
alphabet elif char in alphabet_upper:
= alphabet_upper
alphabet else:
return char
= alphabet.index(char)
code = (code + shift) % len(alphabet)
new_code = alphabet[new_code]
new_char return new_char
- أولاً نبحث عن الحرف في سلسلة الأحرف الصغيرة، ثم الكبيرة، ثم إن لم يوجد في أي منها فإننا نعيد الحرف كما هو، ولا نزيحه
- فإن وجدنا الحرف في إحدى السلسلتين (الكبيرة أو الصغيرة) فإننا نعين المتغير
alphabet
لهذه السلسلة التي سيتم البحث فيها بعد ذلك - نبحث في هذه السلسلة بالفعل
.index()
لنعرف موضِع الحرف، حيث سيكون هذا هو رمزه الرقمي (code
). - نزيح الرقم بالمقدار المعطى (
shift
) ونُدير الناتج بعملية باقي القسمة وهي التعبير: (% len(alphabet)
) - نعين المتغير
new_char
للحرف الذي في موضع الرقم بعد الإزاحة - نعيد الحرف البديل
نختبر الدالة ببعض التوكيادت:
assert encode('a', 3) == 'd'
assert encode('b', 3) == 'e'
assert encode('x', 3) == 'a'
assert encode('y', 3) == 'b'
أما دالة عكس التعمية، فهي ببساطة تعكس الإزاحة بطرح الرقم بعد جمعه.
def decode(char: str, shift: int) -> str:
if char in alphabet_lower:
= alphabet_lower
alphabet elif char in alphabet_upper:
= alphabet_upper
alphabet else:
return char
= alphabet.index(char)
code = (code - shift) % len(alphabet)
new_code = alphabet[new_code]
new_char return new_char
فأما دالة استخراج المعمى، فنريدها أن تكون فعلاً تعكِس، ولذلك سنستعمل التوكيد بتمرير المعمة لعكسه مباشرة بهذه الطريقة:
assert decode(encode('a', 3), 3) == 'a'
assert decode(encode('z', 3), 3) == 'z'
والآن بعد أن تأكدنا من عمل ذلك على مستوى الحرف الواحد، نريد أن نأخذ النص كاملاً فنعميه:
def encode_text(text: str, shift: int) -> str:
= ""
result for char in text:
+= encode(char, shift)
result return result
- نبدأ بنص فارغ:
result = ""
- نأتي على الحروف حرفًا حرفًا كما في النص
text
ونستعمل فعل التعميةencode
لذلك النص، ونضيف الحرف العائد إلى النص الناتجresult
أما عكس التعمية فباستعمال decode
بدلاً من encode
بمثل ما تقدَّم:
def decode_text(text: str, shift: int) -> str:
= ""
result for char in text:
+= decode(char, shift)
result return result
والآن نريد أن نختبر، ولذلك سنستعين بموقع تفاعلي قد تم فيه عمل ذلك قبلنا، وهو موقع: cryptii.com فنأخذ النص ونستعمله ونتأكد أن ما نخرج به نفس ما خرجوا به:
assert (
"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) ==
encode_text("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"
)
أخيرًا نستعمل ذلك بعد أن تأكدنا من صحته كاملاً:
= "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."
text
print("## Text")
print(text)
= encode_text(text, 3)
text_encoded = decode_text(text_encoded, 3)
text_decoded
print("## Encoded")
print(text_encoded)
print("## Decoded")
print(text_decoded)
## 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.
## Encoded
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.
## Decoded
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.