abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
9 تمثيل النص
ترميز الحروف هي عملية تعيين أرقام للأحرف الرسومية مما يسمح بتخزينها ونقلها وتحويلها باستخدام الحواسيب الرقمية.
رموز ASCII تحتوي على 128
حرف للغة الإنجليزية وبعض علامات الترقيم. منها 95
فقط هي أحرف قابلة للطباعة أما البقية فتسمى أحرف تحكُّم (مثل حرف السطر الجديد \n
، وحرف الرجوع لبداية السطر \r
).
ثم امتدت عن طريق رموز ANSII لتغطي أحرف إضافية (من 128
إلى 255
) وهي الأحرف الاتينية للغات الأخرى.
لنستكشف السلاسل عن طريق حزمة من المكتبة الأساسية string
. الآتي الأحرف اللاتينية الكبيرة والصغيرة، وعلامات الترقيم:
9.1 ترميز Unicode
واليوم رموز Unicode تحتوي على أكثر من مليون حرف لتغطية لغات العالم كافة: اللاتينية، اليونانية، السيريلية، الأرمنية، العبرية، العربية، السريانية، الثانا، الديفاناغارية، البنغالية، الجورموخية، الأورية، التاميلية، التيلوغوية، الكانادية، المالايالامية، السنهالية، التايلاندية، اللاوية، التبتية، الميانمارية، الجورجية، الهانغول، الإثيوبية، الشيروكية، الرموز الكندية الأصلية، الخميرية، المنغولية، الهان (الأيدوغراف الياباني، الصيني، الكوري)، الهيراغانا، الكاتاكانا، واليي. المصدر. وما يزال أول 128
حرف منها متطابق مع رموز ASCII.
مثال
ماذا يحصل لو كتبنا حروف عربية ثم حاولنا حفظ الملف بترميز ASCII ولم نحفظه بترميز Unicode؟
الخطأ يقول: “This file contains characters in Unicode format which will be lost if you save this file as an ANSI encoded text file. To keep the Unicode information, click Cancel below and then select one of the Unicode options from the Encoding drop down list. Continue?”
9.2 كيف يتم تمثيل النصوص في بايثون؟
تمثيل النصوص في بايثون يكون عن طريق النوع str
؛ يُعرَّف بكتابة سلسلة من الأحرف لكن في الواقع تتحول إلى سلسلة من رموز Unicode (أي: أرقام). هذا يعني أنها قد تكون سلسلة رموز لاتينية أو عربية أو صينية أو غير ذلك مما تحويه رموز Unicode.
الفعل المبني ord() تقوم بتحويل الحرف إلى رقم الرمز. بينما chr() تعكس ذلك (من الرمز إلى الحرف).
على النقيض من سي وجافا؛ لا يوجد نوع خاص بالحرف الواحد (char
) في بايثون.
print(ord("A"), ord("Z"))
print(chr(65), chr(90))
print(ord("a"), ord("z"))
print(ord("0"), ord("9"))
65 90
A Z
97 122
48 57
ماذا عن الحروف العربية؟ أين تقع في أرقام ترميز Unicode؟
# Arabic Unicode points are between 1536 and 1791
print(ord("أ"), hex(ord("أ")))
print(ord("ب"), hex(ord("ب")))
print(ord("ي"), hex(ord("ي")))
print(ord('َ'), hex(ord('َ')))
print(ord('ُ'), hex(ord('ُ')))
1571 0x623
1576 0x628
1610 0x64a
1614 0x64e
1615 0x64f
لمعرفة أرقام الحروف في نصٍّ ما؛ نستعمل التكرار هكذا:
def get_unicode_points(s):
codes = []
for c in s:
codes.append(ord(c))
return codes
print(get_unicode_points('Arabian'))
print(get_unicode_points('السَّلَامُ عَلَيْكُمْ'))
[65, 114, 97, 98, 105, 97, 110]
[1575, 1604, 1587, 1614, 1617, 1604, 1614, 1575, 1605, 1615, 32, 1593, 1614, 1604, 1614, 1610, 1618, 1603, 1615, 1605, 1618]
فهذه هي الحروف في الواقع، إلا أننا نتعامل مع شيء مجرَّد في لغات البرمجة العالية غالبًا ما يسمى str
.
راجع ويكيبيديا: النص العربي في Unicode لمزيد من التفاصيل.
الأحرف البيضاء
الأحرف في الأجهزة الرقمية على نوعين:
- أحرف طباعة: مثلاً: الأحرف اللاتينية والأرقام وعلامات الترقيم
- أحرف تحكم: مخفيَّة؛ والغرض منها التحكم بمعالج هذا النص
لعرض الأحرف القابلة للطباعة في محارف آسكي (ASCII)، لدينا المتغير printable
من مكتبة string
:
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
كانت أحرف التحكُّم تستخدم لرن جرس الآلة الطابعة ، والتحكم بها ، لكن اليوم الذي يُستخدم منها غالبًا هو الأحرف البيضاء (Whitespace Characters) ويشمل ذلك الأحرف التالية:
- space:
\s
ويمثل المسافة التي بين الكلمات - tab:
\t
ويمثل المسافة التي بين أعمدة الجداول - linefeed:
\n
تعليمة سطر جديد - return:
\r
تعليمة العودة لبداية السطر الجديد - formfeed:
\f
تعليمة الصفحة الجديدة - vertical tab:
\v
تعليمة العمود الجديد - backspace:
\b
تعليمة عودة المؤشر بمقدار حرف واحد للكتابة فوق الحرف السابق
أما الثلاثة الأخيرة فقد كانت تستخدم فيما مضى، لكن اليوم المستخدم هو الأربعة الأولى فقط. ويجدر بالذكر أن ملفات نصوص نظام ويندوز تستعمل \r\n
للانتقال لسطر جديد بينما تستعمل الأنظمة الأخرى \n
فقط.
تذكر أن بايثون تعتمد على space
و tab
للمسافة البادئة للسطر (indentation)، لتحديد نطاقات الكود بحسب المحاذاة العمودية.
يهمنا هنا الأحرف البيضاء لأنها تظهر في النصوص وقد تكون مزعجة عند معالجتها. لنلقي نظرة على ثلاثة من الأحرف البيضاء: المسافة (space)، التبويب (tab)، وتعليمة السطر الجديد (linefeed).
لاحظ أن طول السلسلة النصية هو عدد الأحرف في السلسلة، سواء كانت قابلة للطباعة (printable) أو أحرف بيضاء (whitespace).
الأطراف الزائدة
لاحظ أن هذا الفعل سيزيل الأحرف البيضاء من بداية ونهاية السلسلة النصية، ولكن ليس الأحرف البيضاء في منتصف السلسلة
قبل:
بعد:
تجزئة النص
انظر: Splitlines
إذا تركنا الكود كما هو في السطر من غير print
فإن ذلك يعرض السلسلة النصية كما هي (بما في ذلك أحرف المسافات البيضاء)
أما إذا وضعنا print
فإنه يطبع الأحرف المرئية ، وينسِّقُ المظهر بناءً على أحرف التحكُّم المخفية:
إذا لم نحدد محدد الفاصل فإن الفاصل الافتراضي هو المسافة.
هنا نحدد الفاصل أنه الحرف "l"
:
لإزالة الأحرف البيضاء جميعها؛ نستعمل التكرار هكذا:
text = '\t hello world \n\n\n'
sp = text.split()
print('split:', sp)
clean = ' '.join(sp)
print('clean:', clean)
split: ['hello', 'world']
clean: hello world
الفصل في الداخل ينتج قائمة من النصوص، بعضها فارغ لوجود الأحرف البيضاء المتتالية، فلا تتضمن في القائمة الناتجة.
9.3 الطباعة
حروف التحكم بآلة الطباعة
يسمّى الحرف \r
بالعودة للبداية لأنه يعني فعل يقوم بإرجاع المؤشر إلى بداية السطر.
كانت آلة الطباعة قديمًا يتحرك رأس الطباعة فيها بعد طباعة كل حرف. ثم عندما ينتهي السطر، يجب على الشخص أن يقوم بعمليتين:
- الضغط على المفتاح الذي يرفع الورقة بمقدار سطر (ويرمز له بالحرف
\r
) - الضغط على المفتاح الذي يرجع رأس الطباعة لبداية السطر (ويرمز له بالحرف
\n
)
وهما مستخدمان اليوم فيما يُعرض على الشاشة.
ففعل print
في الحقيقة يضع سطرًا جديدًا (حرف \n
) في الوضع الافتراضي. فإن أردنا ألا يضعه، فنحدد العامل end
الذي فيه على النحو التالي:
لاحظ أننا جعلنا (end=''
) أي: لا نريده أن يضع حرفًا بعد طباعة النص. ولذلك ظهرت الكلمتان في نفس السطر.
ولو أردت أن تعيد الكتابة على نفس السطر، يمكنك أن تضع الحرف (\r
) الذي يفعل رأس الطباعة بالرجوع لبداية السطر:
لاحظ أن النتيجة هي طباعة الحرفين 45
فوق الحرفين 12
مع بقاء الحرف الأخير 3
في الأخير. وذلك لرجوع رأس الطباعة.
تستعمل هذه اللطيفة في تحديث العداد حتى يظهر على الشاشة وكأنه يزيد شيئًا فشيئًا. وذلك على النحو التالي (لاحظ أننا نستعمل time.sleep(t)
حتى نمثِّل وجود عمليَّة تأخذ وقتًا طويلاً فحسب):