من أين يأتي موخباكس؟ أساسيات الترميزات


تستكشف هذه المقالة المفاهيم الأساسية الكامنة وراء ترميز الأحرف ثم تغوص في التفاصيل الفنية لأنظمة الترميز.


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


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


سأذهب لمعرفة كيفية عمل ترميزات البايت الواحد (ASCII و Windows-1251 وما إلى ذلك) وتاريخ كيفية ظهور Unicode والتشفيرات القائمة على Unicode UTF-8 و UTF-16 وكيف تختلف ، ميزات محددة ، والتوافق ، وعدم وجودها بين الترميزات المختلفة ، ومبادئ ترميز الأحرف ، ودليل عملي لكيفية ترميز الأحرف وفك تشفيرها.


على الرغم من أن ترميز الأحرف قد لا يكون موضوعًا حديثًا ، إلا أنه من المفيد فهم كيفية عمله الآن وكيف كان يعمل في الماضي دون إنفاق الكثير من الوقت.


تاريخ يونيكود


أعتقد أنه من الأفضل أن نبدأ قصتنا من الوقت الذي كانت فيه أجهزة الكمبيوتر في أي مكان بالقرب من تقدم أو شائع كجزء من حياتنا كما هي الآن. لم يكن لدى المطورين والمهندسين الذين كانوا يحاولون التوصل إلى معايير في ذلك الوقت أي فكرة أن أجهزة الكمبيوتر والإنترنت ستكون ذات شعبية هائلة ومتفشية مثلما فعلت. عندما حدث ذلك ، كان العالم بحاجة إلى ترميزات الأحرف.


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


ولكن ما هو أسكي؟ يتكون كود ASCII من 8 بتات. توضح بعض العمليات الحسابية السهلة أن مجموعة الأحرف هذه تحتوي على 256 رمزًا (ثمانية بتات وأصفار والرموز 2⁸ = 256).


تم استخدام أول 7 بتات - 128 رمزًا (2⁷ = 128) في المجموعة للحروف اللاتينية وشخصيات التحكم (مثل فواصل الأسطر الصلبة وعلامات التبويب وما إلى ذلك) والرموز النحوية. البتات الأخرى كانت للغات الوطنية. بهذه الطريقة ، يكون أول 128 حرفًا هو نفسه دائمًا ، وإذا كنت ترغب في ترميز لغتك الأم ، فاستعن بالرموز المتبقية.


وأدى ذلك إلى مجموعة من الترميزات الوطنية. ينتهي بك المطاف بموقف مثل هذا: قل أنك في روسيا تقوم بإنشاء ملف نصي والذي سيستخدم افتراضياً Windows-1251 (الترميز الروسي المستخدم في Windows). وترسل وثيقتك إلى شخص خارج روسيا ، يقول في الولايات المتحدة. حتى إذا كان المستلم يعرف اللغة الروسية ، فسيكون محظوظًا عند فتح المستند على جهاز الكمبيوتر الخاص بهم (مع برنامج معالجة النصوص باستخدام ASCII كرمز افتراضي) لأنهم سيشاهدون شخصيات غريبة مشوهة (mojibake) بدلاً من الحروف الروسية . بتعبير أدق ، ستظهر أي أحرف إنجليزية على ما يرام ، لأن الرموز الـ 128 الأولى في Windows-1251 و ASCII متطابقة ، لكن حيثما يوجد نص روسي ، سوف يستخدم برنامج معالجة النصوص الخاص بالمستلم لدينا الترميز الخاطئ ما لم يقم المستخدم بتعيين الحرف الصحيح يدويًا الترميز.


المشكلة مع معايير رمز الحرف الوطني واضحة. وفي النهاية ، بدأت هذه الرموز الوطنية تتكاثر ، وبدأ الإنترنت بالانفجار ، وأراد الجميع الكتابة بلغته الوطنية دون إنتاج هذه الرموز غير القابلة للتشفير.


كان هناك خياران في هذه المرحلة - استخدام ترميز لكل بلد أو إنشاء خريطة أحرف عالمية لتمثيل جميع الشخصيات على هذا الكوكب.


التمهيدي القصير على أسكي


قد يبدو الأمر أوليًا بشكل مفرط ، لكن إذا كنا سنكون شاملين ، فعلينا أن نغطي جميع القواعد.



هناك 3 مجموعات من الأعمدة في جدول ASCII:


  • القيمة العشرية للحرف
  • القيمة السداسية العشرية للشخصية
  • الصورة الرمزية للشخصية نفسها

دعنا نقول أننا نريد ترميز كلمة "موافق" في ASCII. الحرف "o" له قيمة عشرية من 111 و 6 F بالست عشري. في ثنائي سيكون - 01101111. الحرف "k" هو الموضع 107 في عشري و 6 B في ست عشري ، أو - 01101011 في ثنائي. لذا فإن كلمة "OK" في ASCII ستبدو 01101111 01101011. ستكون عملية فك الترميز هي العكس. نبدأ بـ 8 بت ، ونترجمها إلى ترميز عشري وينتهي بنا المطاف برقم الأحرف ، ونبحث في الجدول عن الرمز المقابل.


يونيكود


مما سبق ، يجب أن يكون من الواضح سبب الحاجة إلى خريطة شخصية واحدة مطلوبة. ولكن كيف سيبدو؟ الجواب هو Unicode وهو في الواقع ليس ترميزًا ، لكنه مجموعة حروف. وهي تتألف من 1114112 موضعًا ، أو نقاط رمز ، معظمها لا تزال فارغة ، لذلك فمن غير المحتمل أن تحتاج المجموعة إلى توسيع.


يتكون معيار Unicode من 17 طائرة مع 65536 نقطة رمز لكل منهما. كل طائرة تحتوي على مجموعة من الرموز. المستوى صفر هو المستوى الأساسي متعدد اللغات حيث نجد الأحرف الأكثر استخدامًا في جميع الحروف الهجائية الحديثة. الطائرة الثانية تحتوي على شخصيات من اللغات الميتة. هناك حتى طائرتان محجوزة للاستخدام الخاص. معظم الطائرات لا تزال فارغة.


يحتوي Unicode على نقاط رمز من 0 إلى 10FFFF (بالسداسي عشري).


يتم تشفير الأحرف بالتنسيق الست عشري مسبوقًا بـ "U +". لذلك ، على سبيل المثال ، تتضمن المستوى الأساسي الأول الأحرف من U + 0000 إلى U + FFFF (من 0 إلى 65،535) ، بينما تحتوي المجموعة 17 على U + 100000 عبر U + 10FFFF (من 1،048،576 إلى 1،114،111).


لذا ، فبدلاً من مجموعة من الترميزات المتعددة ، لدينا جدولًا شاملاً يشفر جميع الرموز والأحرف التي قد نحتاجها في أي وقت. لكنها لا تخلو من عيوبها. بينما تم تشفير كل حرف مسبقًا بواسطة بايت واحد ، يمكن الآن تشفيره باستخدام أرقام مختلفة من البايتات. على سبيل المثال ، اعتدت أن تحتاج فقط إلى بايت واحد لترميز كل الحروف في الأبجدية الإنجليزية. على سبيل المثال ، الحرف اللاتيني "o" في Unicode هو U + 006F. بمعنى آخر ، نفس الرقم الموجود في ASCII - 6F بالأرقام الست عشرية و 111 بالثنائي. ولكن لتشفير الرمز "U + 103D5" (الرقم الفارسي "100") ، نحتاج إلى 103D5 بالسداسي و 66،517 بالترتيب العشري ، والآن نحتاج إلى ثلاث بايت.


يجب معالجة هذا التعقيد بواسطة ترميزات Unicode مثل UTF-8 و UTF-16. وعلاوة على ذلك ، سنلقي نظرة عليها.


UTF-8


UTF-8 هو ترميز Unicode لنظام الترميز ذي العرض المتغير والذي يمكن استخدامه لعرض أي رمز Unicode.


ماذا نعني عندما نتحدث عن متغير العرض؟ بادئ ذي بدء ، نحتاج أن نفهم أن الوحدة الهيكلية (الذرية) في الترميز هي بايت. يعني ترميز العرض المتغير أنه يمكن ترميز حرف واحد باستخدام أرقام مختلفة من الوحدات أو البايتات. على سبيل المثال ، يتم تشفير الحروف اللاتينية مع بايت واحد ، والحروف السيريلية مع اثنين.


قبل أن نمضي قدمًا ، هناك جانب بسيط فيما يتعلق بالتوافق بين ASCII و UTF.


حقيقة أن الحروف اللاتينية وأحرف التحكم الرئيسية مثل فواصل الأسطر ، علامات الجدولة ، إلخ. يحتوي على بايت واحد يجعل ترميز UTF متوافقًا مع ASCII. بمعنى آخر ، يتم العثور على أحرف النص والخطاب اللاتيني في نقاط الشفرة نفسها بالضبط في ASCII و UTF ويتم تشفيرها باستخدام بايت واحد في كليهما ، وبالتالي فهي متوافقة مع الإصدارات السابقة.


دعنا نستخدم الحرف "o" من مثال ASCII الخاص بنا من قبل. تذكر أن موضعها في جدول ASCII هو 111 ، أو 01101111 في ثنائي. في جدول Unicode ، يكون U + 006F ، أو 01101111. والآن نظرًا لأن UTF هو نظام ترميز متغير العرض "o" سيكون بايت واحد. بمعنى آخر ، سيتم تمثيل كلمة "o" بالطريقة نفسها في كليهما. ونفس الشيء بالنسبة للأحرف من 0 إلى 128. لذا ، إذا كان المستند يحتوي على أحرف إنجليزية ، فلن تلاحظ فرقًا إذا فتحته باستخدام UTF-8 أو UTF-16 أو ASCII ، وستلاحظ فرقًا فقط إذا بدأت العمل مع الترميزات الوطنية.


دعونا نلقي نظرة على كيفية ظهور العبارة المختلطة الإنجليزية / الروسية "Hello World" في ثلاثة أنظمة ترميز مختلفة: Windows-1251 (ترميز روسي) ، ISO-8859-1 (نظام تشفير للغات أوروبا الغربية) ، UTF-8 (Unicode) . هذا المثال يوضح لأنه لدينا عبارة بلغتين مختلفتين.



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


لنفترض أن العبارة الأصلية كانت مكتوبة بترميز Windows-1251. عندما ننظر إلى الجدول أعلاه ، يمكننا أن نرى من خلال الترجمة من عشري أو عشري إلى عشري أن نحصل على الترميز أدناه في ثنائي باستخدام Windows-1251.


01001000 01100101 01101100 01101100 01101111 00100000 11101100 11101000 11110000


حتى الآن لدينا عبارة "Hello World" في ترميز Windows-1251.


الآن تخيل أن لدينا ملف نصي لكننا لا نعرف نظام الترميز الذي تم حفظ النص فيه. نفترض أنها مشفرة في ISO-8859-1 وفتحها في معالج النصوص الخاص بنا باستخدام نظام الترميز هذا. كما رأينا سابقًا ، تظهر بعض الأحرف على ما يرام ، لأنها موجودة في نظام الترميز هذا ، وحتى في نقاط الرمز نفسها ، لكن الأحرف الموجودة في الكلمة الروسية "العالم" لا تعمل جيدًا أيضًا. لا توجد هذه الأحرف في نظام الترميز ، وفي أماكنها أو نقاط الرمز ، في ISO-8859-1 نجد أحرفًا مختلفة تمامًا. إذن "m" هي الكود 236 ، "و" 232 ، و "p" 240. لكن في ISO-8859-1 ، تتوافق نقاط الكود هذه مع "ì" (236) ، "è" (232) ، و " ð "(240).


لذا ، فإن عبارة "Hello World" المختلطة التي تم تشفيرها في نظام التشغيل Windows-1251 والقراءة في ISO-8859-1 ستبدو "Hello ìèð". لدينا توافق جزئي ولا يمكننا عرض عبارة مشفرة في نظام ما بشكل صحيح في النظام الآخر ، لأن الرموز التي نحتاجها ببساطة غير موجودة في الترميز الثاني.


نحتاج إلى تشفير Unicode - في حالتنا ، سنستخدم UTF-8 كمثال. لقد ناقشنا بالفعل أن الأحرف يمكن أن تأخذ ما بين 1 إلى 4 بايت في UTF-8 ، ولكن الميزة الأخرى هي أن UTF ، على عكس نظامي التشفير السابقين ، لا يقتصر على 256 رمزًا ، ولكنه يحتوي على جميع الرموز في مجموعة أحرف Unicode .


إنه يعمل بشكل مثل هذا: أول جزء من كل حرف مشفر لا يتوافق مع الصورة الرمزية أو الرمز نفسه ، ولكن مع بايت معين. لذا ، إذا كانت البتة الأولى صفراً ، فنحن نعرف أن الرمز المشفر يستخدم بايت واحد فقط - مما يجعل المجموعة متوافقة مع ASCII. إذا نظرنا عن كثب إلى جدول رموز ASCII ، فقد رأينا أن أول 128 رمزًا (الأبجدية الإنجليزية ، وشخصيات التحكم ، وعلامات الترقيم) يتم التعبير عنها بالثنائي ، فكلها تبدأ بقيمة صغيرة قدرها 0 (لاحظ أنك إذا قمت بترجمة الأحرف إلى ثنائي باستخدام محول عبر الإنترنت أو أي شيء مشابه ، قد يتم تجاهل أول بت من الدرجة الأولى الصفرية ، مما قد يكون مربكًا بعض الشيء).


01001000 - قيمة البتة الأولى هي 0 ، لذلك 1 بايت يشفر حرف واحد -> "H".


01100101 - قيمة البتة الأولى هي 0 ، لذلك ترمز البايتة الواحدة إلى حرف واحد> "e".


إذا كانت قيمة البتة الأولى ليست صفرية ، فسيتم تشفير الرمز بعدة بايت.


سيكون الترميز ثنائي البايتات 110 لقيم الثلاثة بت الأولى.


11010000 10111100 - بتات العلامة هي 110 و 10 ، لذلك نستخدم 2 بايت لترميز حرف واحد. دائمًا ما تبدأ البايتة الثانية في هذه الحالة بالرقم "10." ولذا فإننا نحذف بتات التحكم (بتات الرصاص التي يتم تمييزها باللون الأحمر والأخضر) وننظر إلى بقية الكود (10000111100) ، ونتحول إلى ست عشري (043) -> U + 043C الذي يعطينا الروسية "م" في يونيكود.


البتات الأولية للحرف ثلاثية البايت هي 1110.


11101000 10000111 101010101 - نضيف كل البتات باستثناء وحدات التحكم ونجد أنه في العشرية لدينا 103B5 ، U + 103D5 - الرقم الفارسي القديم مائة (10000001111010101).


تبدأ ترميزات الأحرف المكونة من أربعة بايتات بتات الرصاص 11110.


11110100 10001111 10111111 10111111 - U + 10FFFF وهو آخر حرف متوفر في مجموعة Unicode (100001111111111111111).


الآن ، يمكننا بسهولة كتابة عبارة متعددة اللغات بترميز UTF-8.


UTF-16


UTF-16 هو ترميز آخر متغير العرض. الفرق الرئيسي بين UTF-16 و UTF-8 هو أن UTF-16 يستخدم 2 بايت (16 بت) لكل وحدة كود بدلاً من 1 bye (8 بت). بمعنى آخر ، يمكن أن يكون أي حرف Unicode مشفرًا في UTF-16 إما بايتين أو أربعة بايت. لإبقاء الأمور بسيطة ، سأشير إلى هاتين البايتتين كوحدة رمز. لذلك ، في UTF-16 ، يمكن تمثيل أي شخصية باستخدام إما وحدة واحدة أو وحدتي كود.


لنبدأ بالرموز المشفرة باستخدام وحدة رمز واحدة. يمكننا بسهولة حساب أن هناك 65،535 حرفًا (216) حرفًا مع وحدة رمز واحدة ، والتي تصطف بالكامل مع المستوى الأساسي متعدد اللغات في Unicode. سيتم تمثيل جميع الأحرف في هذه الطائرة بوحدة رمز واحدة (وحدتي بايت) في UTF-16.


حرف لاتيني "o" - 00000000 01101111.


الحرف السيريلي "M" - 00000100 00011100.


الآن دعنا نفكر في شخصيات خارج المستوى الأساسي متعدد اللغات. هذه تتطلب وحدتي كود (4 بايت) ويتم ترميزهما بطريقة أكثر تعقيدًا قليلاً.


أولاً ، نحن بحاجة إلى تحديد مفهوم الزوج البديل. الزوج البديل عبارة عن وحدتي كود تستخدم لتشفير حرف واحد (يبلغ إجماليه 4 بايت). تحتفظ مجموعة أحرف Unicode بنطاق خاص من D800 إلى DFFF للأزواج البديلة. هذا يعني أنه عند تحويل زوج بديل إلى بايت في ست عشري ، فإننا في نهاية المطاف مع نقطة رمز في هذا النطاق وهو زوج بديل بدلاً من حرف منفصل.


لتشفير رمز في النطاق من 10000 إلى 10FFFF (على سبيل المثال ، الأحرف التي تتطلب أكثر من وحدة رمز واحدة) نتابع ما يلي:


  1. اطرح 10000 (ست عشري) من نقطة الرمز (هذا هو أدنى نقطة رمز في النطاق 10000 - 10FFFF).


  2. لقد انتهى الأمر بعدد يصل إلى 20 بت لا يزيد عن FFFF.


  3. تتم إضافة 10 بت عالي الترتيب الذي انتهى بنا الأمر إلى D800 (أدنى نقطة رمز في نطاق الزوج البديل في Unicode).


  4. تتم إضافة وحدات البت 10 التالية إلى DC00 (أيضًا من نطاق الزوج البديل).


  5. بعد ذلك ، ننتهي بوحدتين رمزيتين 16 بت بديلة ، أول 6 بتات تعرّف الوحدة كجزء من زوج بديل.


  6. يحدد البت العاشر في كل بديل ترتيب الزوج. إذا كان لدينا حرف "1" ، فإنه البديل الأول أو الأعلى ، وإذا كان لدينا الرقم "0" ، فهو البديل البديل أو المنخفض.



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


لنرمز ثم فك شفرة الرقم الفارسي مائة (U + 103D5):


  1. 103D5 - 10000 = 3D5.


  2. 3D5 = 0000000000 1111010101 (أعلى 10 بتات صفرية ، وعندما يتم تحويلها إلى ست عشرية ، ينتهي بنا المطاف بـ "0" (العشرة الأولى) ، و 3 D5 (العشرة الثانية)).


  3. 0 + D800 = D800 (1101100000000000) تخبرنا أول 6 بتات أن نقطة الكود هذه تقع في نطاق الزوج البديل ، وأن البتة العاشرة (من اليمين) لها قيمة "0" ، لذلك هذا هو البديل الأعلى.


  4. 3D5 + DC00 = DFD5 (1101111111010101) تخبرنا البتات الستة الأولى أن نقطة الكود هذه تقع في نطاق الزوج البديل ، البتة العاشرة (من اليمين) هي "1" ، لذلك نحن نعرف أن هذا هو البديل المنخفض.


  5. يبدو الحرف الناتج المشفر في UTF-16 - 1101100000000000 1101111111010101.



الآن دعونا فك شفرة الحرف. دعنا نقول لدينا نقطة التعليمات البرمجية التالية - 1101100000100010 1101111010001000:


  1. نقوم بالتحويل إلى رقم سداسي عشري = D822 DE88 (تقع كلتا نقطتي الكود في نطاق الزوج البديل ، لذلك نعرف أننا نتعامل مع زوج بديل).


  2. 1101100000100010 - البت العاشر (من اليمين) هو "0" ، لذلك هذا هو البديل الأعلى.


  3. 1101111010001000 - البتة العاشرة (من اليمين) هي "1" ، لذلك هذا هو البديل المنخفض.


  4. نتجاهل الـ 6 بتات التي تحدد هذا الأمر كبديل ويتم تركها مع 0000100010 1010001000 (8A88).


  5. نضيف 10000 (أدنى نقطة رمز في النطاق البديل) 8A88 + 10000 = 18A88.


  6. ننظر إلى جدول Unicode لـ U + 18A88 = Tangut Component-649.



مجد لكل من قرأ هذا الآن!


آمل أن يكون هذا بالمعلومات دون أن يتركك بالملل.


قد تجدها مفيدة أيضًا:

مجموعة أحرف يونيكود


استراتيجيات لتوطين المحتوى: IP- أو المستندة إلى المستعرض


عن المترجم


يعد Alconost مزودًا عالميًا لخدمات الترجمة للتطبيقات والألعاب ومقاطع الفيديو ومواقع الويب في أكثر من 70 لغة. نحن نقدم ترجمات حسب اللغويين الناطقين باللغة الأم ، والاختبار اللغوي ، وسير العمل المستند إلى مجموعة النظراء ، والتعريب المستمر ، وإدارة المشروع على مدار الساعة طوال أيام الأسبوع ، والعمل مع أي تنسيق لموارد السلسلة. نصنع أيضًا إعلانات ومقاطع فيديو وإعلانات تثقيفية وأفلام دعائية وشروحات ومقاطع فيديو لـ Google Play ومتجر التطبيقات.

Source: https://habr.com/ru/post/ar480688/


All Articles