همهی ما میدانیم که کامپیوترها تنها با اعداد و ارقام سر و کار دارند و تمام اطلاعات نوشتاری، صوتی و تصویری را به صورت اعداد و ارقام پردازش و ذخیره میکنند. حروف، اعداد و علایمی که در اپلیکیشنها مورد استفاده قرار میگیرند، به آن شکلی که شما آنها را میبینید در کامپیوتر مدیریت نمیشوند. برای قابل فهم کردن اطلاعات برای کامپیوتر لازم است برای هر حروف از الفبا، یک عددی اختصاص دهیم. حروف و کاراکترها به مجموعهای از 0 و 1 تبدیل میشود تا مدیریت آنها برای کامپیوتر سادهتر باشد. اختصاص این کدها به اطلاعات توسط سیستمهای کدگذاری انجام خواهد شد. برای این منظور صدها نوع سیستم کدگذاری برای قابل فهم کردن زبانهای مختلف برای کامپیوترها به وجود آمد.
برای زبان فارسی هم تعداد زیادی سیستمهای کدگذاری به وجود آمد. هر شرکت نرمافزاری یک سیستم کدگذاری مخصوص به خودش را داشت. البته وجود تعداد زیاد سیستمهای کدگذاری تنها مختص به زبان فارسی نبوده و بیشتر زبانهای دیگر هم با این مشکل روبرو بودند.
کد اسکی یا ASCII چیست؟
انجمن استانداردهای آمریکا در سال 1960 روش کدگذاری 7 بیتی ASCII را معرفی کرد. ASCII مخفف عبارت American Standard Code for Information Interchange است که در آن زمان شامل 128 کاراکتر یا 7 بیت تعریف شد. ASCII از کد تلگراف تهیه شدهاست. اولین استفاده تجاری آن به عنوان یک کد ماشین تحریر الکترومکانیکی هفت بیتی بود که توسط خدمات داده بل Bell عرضه شد. کار بر روی استاندارد ASCII از ۶ اکتبر ۱۹۶۰ با اولین جلسه انجمن استانداردهای آمریکایی (اکنون موسسه استاندارد ملی آمریکا یا ANSI) آغاز شد.
ASCII بر اساس الفبای انگلیسی، 128 کاراکتر مشخص شده را به صورت عدد صحیح هفت بیتی، همانطور که در جدول ASCII نشان داده شدهاست، کدگذاری میکند. نود و پنج از کاراکتر های کدگذاری شده قابل چاپ هستند: اینها شامل رقمهای ۰ تا ۹، حروف کوچک a تا z، حروف بزرگ A تا Z و نمادهای نقطهگذاری هستند. علاوه بر این، ASCII شامل ۳۳ کد کنترل غیر چاپی بود که از ماشینهای تحریر سرچشمه میگرفتند. بسیاری از این موارد اکنون منسوخ شدهاند، اگرچه تعداد معدودی از آنها هنوز هم بهطور معمول مورد استفاده قرار میگیرند.
استاندارد ارائهشده در آن زمان بیشتر برای زبانهای لاتین کاربرد داشت. پس از آن در دههی 1980 تصمیم گرفتند که این استاندارد به جای استفاده از 7 بیت، از یک بایت کامل استفاده کند. یک بایت کامل شامل 8 بیت و 256 کاراکتر است. از این رو زبانهای دیگر نیز میتوانستند از این استاندارد استفاده کنند. ASCII به روشنی مشخص نکرده که مقادیر بین 128 تا 255 به چه چیزی اختصاص دارد. در بین زبان دیگر استاندارد واحدی وجود نداشت و هر زبانی الفبای خود را با کد مختص به الفبای خود نشان میداد. پس در این زمان به استاندارد واحدی که با تمامی زبانها سازگار باشد و برای هر کاراکتر کد مختص به خود را داشته باشد، نیاز بود. برای حل این مشکل سازندگان کامپیوترها سعی کردند از صفحههای کد (Code Pages) استفاده کنند که از مقادیر تعریف شده 128 تا 255 در ASCII استفاده کرده و آن را به کاراکترهای مختلف مورد نیاز برای نمایش زبانهای دیگر نگاشت میکند. متأسفانه این 128 کاراکتر اضافی برای کل دنیا کافی نبودند؛ صفحههای کد بر اساس زبان کشورها متفاوت هستند و برای مثال صفحه کد روسی، صفحه کد فارسی و غیره پدید آمدند. در این حالت، کاراکتر شماره 200 روی یک کامپیوتر همان کاراکتر شماره 200 روی کامپیوتر دیگر بود. اما باز هم این روش کارساز نبود. تا زمانی که افراد از صفحههای کد یکسانی استفاده کنند، همه چیز خوب پیش میرود اما اگر کد صفحهها برای افراد یکسان نباشد، همه چیز به هم میریزد.
وجود یک استاندارد واحد برای کدگذاری در بین زبانهای مختلف
کلید حل این مشکل وجود یک استاندارد واحد بود. بر این اساس مشخص میشود که هر کدام از این اعداد چه کاراکترهایی را نمایش میدهند. در ابتدا دو استاندارد برای ایجاد مجموعه کاراکترهای واحد صورت گرفت. اولی ISO-10646 و دیگری Unicode بود. اما وجود دو استاندارد باز هم مشکل را به صورت کامل حل نکرد. بر این اساس ISO و Unicode تصمیم گرفتند در سال 1991 به یکدیگر بپیوندند. از این رو با معرفی یونیکُد (unicode) این مشکل حل شد. حال سوال این است که یونیکُد چیست؟
یونیکُد یا Unicode چیست؟
یونیکُد یا همان Universal Character Set Transformation Format یک استاندارد بینالمللی است که برای کدبندی کاراکترها و نمایش و پردازش متون چندزبانه مورد استفاده قرار میگیرد. این استاندارد به صورت کتابی به نام ‘The Unicode Standard’ نیز منتشر شدهاست. یونیکُد در واقع مجموعهای از کاراکترها (charset) با اعداد منحصر به فرد است که به آنها در اصطلاح نقطه کد (Point Code) گفته میشود. هر Point Code کاراکتر واحدی را نمایش میدهد. برای نمونه A به نقطه کد U+0041 نگاشت شد. این نقطه کد به صورت هگزادسیمال بیان شده و همان 65 در سیستم دهدهی است. گروه یونیکُد کار دشوار نگاشت هر کاراکتر در همهی زبانها به یک نقطه کد را به انجام رسانید. زمانی که همهی این نقطه کدها تخصیص یافتند، استاندارد یونیکُد همچنان فضای کافی برای 1 میلیون نقطه کد دیگر نیز داشت که برای همه تمدنهای شناخته شده و حتی کشف نشده آینده نیز فضای کافی ارائه میکند. شما میتوانید نقطه کدها را در ویندوز با مراجعه به مسیر Start Menu > Run > Charmap یا به صورت آنلاین در وبسایت Unicode.org ملاحظه کنید.
یونیکُد مستقل از سیستم عامل و یا برنامه و زبان خاصی، به هر یک از حروف یک کد یکتا اختصاص میدهد. یونیکُد میتواند تمام حروف زبانهای مختلف دنیا را در خود جای دهد. یونیکُد میتواند برای وبسایتها و برنامهها بسیار کاربردی باشد، از این رو که میتوان گفت مهم نیست کاربران از چه وبسایت و یا چه مرورگری استفاده میکنند؛ تنها کافی است از یونیکُد پشتیبانی کند. امروزه اکثر شرکتهای بزرگ دنیای کامپیوتر از این استاندارد استفاده میکنند و همچنین میتوان گفت که تقریبا تمام برنامههای کاربردی جدید با این استاندارد کدگذاری شدهاند. گسترش استاندارد یونیکُد موجب شده تا تمامی فارسی زبانها هم بتوانند در دنیای اینترنت مطالب خود را عرضه کنند. یونیکُد موجب شده تا فرایند ایجاد وبسایتها و برنامههای فارسی بسیار آسانتر و کم هزینهتر باشد.
در زمان طراحی یونیکُد جهت ایجاد تطبیقپذیری (compatibility) با سیستم ASCII، همه نقطه کدها از U+0000 تا U+007F یعنی از 0 تا 127 همان کدهای ASCII بودند. افراد باریکبین احتمالاً از این موضوع راضی نبودهاند، چون مجموعه کامل کاراکترهای لاتین در جای دیگری تعریف شده بود و اینکه یک حرف 1 نقطه کد داشت. ضمناً این وضعیت باعث میشد که کاراکترهای لاتین در اولویت قرار بگیرند در حالی که کاراکترهای چینی، عربی و زبانهای غیراستاندارد در نقطه کدهای بعدی قرار بگیرند که نیازمند 2 بایت برای ذخیرهسازی بود. با این وجود، این طراحی ناگزیر بود، چون ASCII یک استاندارد بود و بسیاری از ابزارها و پروتکلهای ارتباطی تنها کاراکترهای ASCII را میپذیرند و اگر یونیکُد قرار بود از سوی کل دنیا پذیرفته شود، بیشک باید با آن سازگاری میداشت.
اما یک سؤال همچنان بیپاسخ ماند: چگونه میتوانیم یک نقطه کد را به عنوان داده ذخیره کنیم؟ انکودینگ Encoding راه نجات است.
انکودینگ یا همان Encoding چیست؟
تبدیل دادهها به صورتی که سیستم توانایی خواندن و استفاده از آن را داشته باشد Encoding گویند. کدهای یکتا به روشهای متفاوتی در کامپیوتر ذخیره میشوند؛ این روشها را کدگذاری یا Encoding میگویند. میتوان گفت که کدگذاری فرآیند تبدیل دادهها به فرمتهای مورد نیاز است. این کدگذاری شامل تدوین برنامهها، اجرای برنامه انتقال و ذخیرهسازی دادهها و همچنین پردازش دادههای برنامه است.
روشهای کدگذاری یوینکد
یونیکُد به سه روش مختلف کدگذاری میشود؛ UTF-8، UTF-16 و UTF-32. حال سوال این است که UTF چیست؟ تفاوت این روشهای کدگذاری در چیست؟ UTF مخفف عبارت Unicode Transformation Format است که به معنی “فرمت تبدیل یونیکُد” است. UTF روش کدگذاری است که زیر مجموعهای از استاندارد یونیکُد به شمار میرود. در ادامه بیشتر با روشهای کدگذاری یونیکُد و تفاوتهای آنها آشنا خواهید شد.
مقایسه روشهای کدگذاری UTF-8، UTF-16 و UTF-32
از تفاوتهای این سه روش کدگذاری میتوان به نحوهی ارائهی حروف، اعداد و علایم مختلف اشاره کرد. روشهای کدگذاری UTF-8 و UTF-16 هر دو دارای عرض متغیر هستند و میتوانند از حداکثر 4 بایت برای کدگذاری استفاده کنند. اما در حالت حداقل،UTF-8 فقط از یک بایت (معادل 8 بیت) استفاده میکند ولی UTF-16 از 2 بایت (معادل 16 بیت) استفاده میکند. این تفاوت تاثیر زیادی در اندازه فایلهای کدگذاری شده دارد. به زبانی دیگر میتوان گفت که یک فایل کدگذاری شده با UTF-16 تقریبا دو برابر بزرگتر از فایلهای کدگذاری شده با UTF-8 است. UTF-32 برخلاف دو روش قبلی، طول ثابتی دارد و بیشترین فضا را اشغال میکند.
از سوی دیگر میتوان گفت که UTF-8 با ASCII سازگار است اما روش کدگذاری UTF-16 با ASCII ناسازگار است. روش کدگذاری UTF-8 مبتنی بر بایت byte-oriented است و با شبکهها و فایلهای مبتنی بر بایت مشکلی ندارد؛ اما UTF-16 مبتنی بر بایت نیست و برای کار با شبکههای مبتنی بر بایت نیاز به سفارشیسازی دارد. همچنین میتوان گفت که UTF-8 در بازیابی از خطاها در مقایسه با UTF-16 بهتر عمل میکند. در این مواقع UTF-8 میتواند بایت غیر خراب بعدی را رمزگشایی کند. UTF-16 هم در صورت خراب شدن بایتها همین کار را میکند اما زمانی که برخی از بایتها گم شوند، مشکل رخ میدهند. بایت گمشده ترکیبهای بایت را با هم مخلوط میکند و نتیجه نهایی از بین میرود.
UTF-8
UTF-8 مخفف عبارت Unicode Transformation Format 8-bit به معنای فرمت تبدیل یونیکُد 8 بیتی است. UTF-8 یکی از روشهای کدگذاری یک بایتی (معادل 8 بیت) با عرض متغیر است که برای ارتباط الکترونیکی استفاده میشود. در کنفرانس USENIX در سال 1993، UTF-8 به طور رسمی معرفی شد. UTF-8 پرکاربردترین و رایجترین روش برای نمایش متن یونیکُد در صفحات وب است. UTF-8 کدگذاری غالب برای شبکه جهانی وب (و فناوریهای اینترنت) است که تا سال 2022، 98٪ از کل صفحات وب و تا 100.0٪ برای برخی از زبانها را شامل میشود.
در این روش کدگذاری هر کاراکتر با یک تا چهار بایت نمایش داده میشود. UTF-8 با ASCII سازگار است و میتواند هر کاراکتر استاندارد یونیکُد را نشان دهد. این استاندارد رمزگذاری قادر است همهی کد کاراکترها معتبر در یونیکُد را با استفاده از یک تا چهار واحد کد یک بایتی (8 بیتی) رمزگذاری کند. UTF-8 یکی از روشهای رمزگذاری است که توسط سازمان بینالمللی استاندارد (ISO) در ISO-10646 تعریف شده است. این کد میتواند حداکثر 2,097,152 نقطه کد (2^21) را نشان دهد که بیش از اندازه کافی برای پوشش 1,112,064 کاراکتر یا نقطه کد فعلی است.
همان طور که گفته شد، UTF-8 یک استاندارد رمزگذاری “با عرض متغیر” است. حال سوال این است که طول متغییر به چه معنا است؟ این بدان معنی است که هر نقطه کد را با تعداد متفاوتی از بایتها، بین یک تا چهار بایت رمزگذاری میکند. این کار برای صرفهجویی در فضا بسیار مناسب است. نقاط کد رایج مورد استفاده معمولا با بایتهای کمتری نسبت به نقاط کد که به ندرت مورد استفاده قرار میگیرد، کدگذاری میشود. UTF-8 الگوریتمی است که اعداد مربوط به پوینتکدها را به باینری تبدیل میکند. از این رو میتوان آنها را بر روی دیسک ذخیره کرد و یا از طریق شبکه انتقال داد.
شاخصگذاری در کدگذاری یونیکُد
ذخیرهسازی دادهها در چندین بایت باعث بروز مشکلی به نام ترتیب بایت byte order میشود. برخی کامپیوترها بایت کوچکتر را ابتدا ذخیره میکنند و برخی دیگر بایت بزرگ را اول ذخیرهسازی میکنند. از آنجا که در کدگذاری های یونیکُد نیز از چندین بایت برای ذخیرهسازی استفاده میشود این مشکل در کدگذاریهای یونیکُد نیز وجود دارد. برای حل این مشکل میتوانیم کارهای زیر را انجام دهیم:
گزینه 1: انتخاب یک قرارداد
ما یک قرارداد میگذاریم که همه دادههای متنی باید به صورت big-endian یا little-endian باشند. البته این قرارداد پاسخگو نیست، زیرا کامپیوترها در جریان تصمیمگیری ما نیستند و هر بار که فایلی را باز میکنند نمیتوانند تشخیص دهند که از چه ترتیب بایتی باید برای تبدیل آن استفاده کنند.
گزینه 2: همه افراد بر سر یک شاخص ترتیب بایت (BOM) Byte Order Mark توافق میکنند
بدین ترتیب یک هدر Header به ابتدای هر فایل اضافه میشود. انکودینگ های یونیکُد میتوانند نقطه کد U+FEFF را به عنوان هدر فایل بنویسند. اگر یک رشتهی کدگذاری شده یونیکُد را باز کنید و با عبارت FEFF مواجه شوید، دادههایی که در ترتیب صحیح بایت قرار دارند میتوانند به صورت مستقیم استفاده شوند. اگر با FFFE مواجه شود به این معنی است که دادهها از کامپیوتری با نوع متفاوت میآیند و باید به معماری مورد نظر شما تبدیل شوند. بدین ترتیب باید همه بایتهای موجود در فایل معکوس شوند. اما متأسفانه همه مسائل به این سادگی نیستند. BOM در واقع یک کاراکتر معتبر یونیکُد است. اگر فردی فایلی بدون یک هدر ارسال کند و آن کاراکتر در واقع بخشی از فایل باشد چه رخ میدهد؟ این وضعیت همچنان یک مشکل حل نشده در یونیکُد محسوب میشود. پیشنهاد شده است که از کاراکتر U+FEFF و U+FFFE به جز در هدر فایل اجتناب و از کاراکترهای جایگزین به جای آن استفاده شود. این وضعیت مشاهده شماره 2 طراحی یونیکُد را مشخص میسازد: دادههای چند بایتی مشکل ترتیب بایت را دارند! در استاندارد ASCII هرگز در مورد ترتیب بایت دغدغهای وجود ندارد. در این سیستم هر کاراکتر یک بایت منفرد است و نمیتواند به صورت نادرستی تفسیر شود. اما در عمل وقتی بایتهای 0xFEFF یا 0xFFEE را در ابتدای فایل میبینید این احتمال وجود دارد که یک BOM در یک فایل متنی یونیکُد است. این کاراکترها به احتمال زیاد یک نشانگر برای ترتیب بایت هستند.
جمعبندی
همان طور که گفته شد کامپیوترها برای اینکه بتوانند اطلاعات نوشتاری، صوتی و تصویری را پردازش کنند به کدهایی که به صورت اعداد و ارقام باشد نیاز دارد. برای این کدگذاری روشهای مختلفی از جمله ASCII وجود دارد. یکی از روشهای استاندارد و مشترک در بین زبانهای مختلف جهان میتوان به یونیکُد اشاره نمود. یونیکُد هم برای کدگذاری از سه روش مختلف استفاده کرده است که UTF-8 رایجترین و کاربردیترین است. دلیل محبوبیت بالای این روش کدگذاری سازگاری با ASCII است. UTF-8 تمامی کاراکترهای ASCII را تنها در یک بیت قرار میدهد. پس میتوان گفت که UTF-8 هم با نسخههای قدیمی کدگذاری سازگار است و هم برای زبانهای لاتین بهینهتر است.