UTF-8
תיאור הקידוד

הקידוד ב-UTF-8 הוא תלוי תו, או נכון יותר תלוי במספר המייצג את התו בתקן היוניקוד. לכל תו ברפרטואר התווים של יוניקוד יש מספר המייצג אותו. קיימים תווים שמסיבות של תאימות או סיבות אחרות חוזרים מספר פעמים ברפטואר אך לכל אחד מהם מספר שונה. כל מספר מייצג תו אחד בלבד ולכן ניתן, ואולי אף עדיף, לדבר על התווים דרך מספריהם הייצוגיים ולא דרך שמותיהם, כדי למנוע בלבול. נהוג לרשום את המספרים המייצגים את התווים בצורה הקסדצימלית בשל קלות ההמרה מצורה זו לצורה הבינארית שהיא הצורה בה נכתבים המספרים למחשב. נהוג גם, כאשר מדברים על תווים או המספרים המייצגים אותם, לנקוט בסימונים מיוחדים המבהירים שמדובר ביוניקוד:
אם התו (קרי, המספר המייצג אותו) נמצא בטווח שבין 0x00000000 ל-0x0000FFFD, נאמר שהתו נמצא במשטח הרב-לשוני הבסיסי ונכתוב רק את ארבע הספרות האחרונות של המספר עם הקידומת U+. לדוגמה, המספר המייצג את האות אל"ף ביוניקוד הוא 0x000005D0, ולכן נתייחס אליה בתור U+05D0. המשטח הרב-לשוני הבסיסי טומן בחובו את מרבית התווים בהם השתמשו ומשתמשים גם היום.
אם המספר גדול מ-0x0000FFFD, נאמר שהוא מחוץ למשטח הרב-לשוני הבסיסי ונכתוב את כל ספרות המספר המייצג עם הקידומת U-. משטחים אלה מכילים בתוכם תווים רבים שהשימוש בהם מועט לרוב, לדוגמה: תווים מוזיקליים, סימנים מתמטיים ואותיותיהן של שפות היסטוריות.
כאשר נאמר U+05D0 נתכוון בעצם לאות אל"ף (א') כפי שהיא מוגדרת בתקן היוניקוד. כאשר נאמר 0x05D0 נתכוון בעצם למספר מסוים (שבמקרה מייצג ביוניקוד את האות אל"ף). משום שמדובר אך ורק במספר, נוכל לכותבו בכל צורה שנחפוץ כל עוד ערכו זהה. נוכל לרשום למשל גם 0x000005D0, או 1488, שהוא ערכו של המספר בבסיס העשרוני (ראו בסיס ספירה) – ממש כפי שאין הבדל אם נרשום 2 או 2.0 או 002 מבחינת ערך המספר.
הקידוד ב-UTF-8 פועל לפי מספר עקרונות פשוטים:
התווים U+0000 עד U+007F (שהם תווי ASCII שכזכור ערכיהם נעים בין 0 ל-127) מומרים פשוט למספרים 0x00 עד 0x7F בהתאמה ומקודדים לבית אחד. מספרים אלו קטנים, ודי ב-7 סיביות כדי לייצגם ולכן בכל בית בו מקודד אחד מהתווים הנ"ל, תהיה הסיבית המשמעותית ביותר כבויה (ערכה 0). משום שכל תווי ה-ASCII מקודדים ב-UTF-8 באמצעות בית אחד, אנו מקבלים שטקסט המקודד ב-ASCII, מקודד בדיוק באותה הצורה ב-UTF-8. דבר זה נותן לנו תאימות לאחור ל-ASCII.
תווים מעבר ל-U+007F יקודדו באמצעות מספר בתים (בפועל, שניים עד ארבעה בתים). הסיבית המשמעותית ביותר בכל אחד מהבתים הללו תהיה דלוקה (ערכה יהיה 1). הבחירה בכמה בתים להשתמש תלויה בערך המספר הייצוגי, מספרים בטווח 0x0007FF–0x000080 יקודדו באמצעות שני בתים, מספרים בטווח 0x00FFFF–0x000800 יקודדו באמצעות שלושה בתים ומספרים גדולים יותר (מספרים בטווח 0x10FFFF–0x010000) יקודדו באמצעות ארבעה בתים. הקידוד תוך שימוש ברצף של בתים כדי לייצג תו אחד ייעשה כך:
הבית הראשון יתחיל ברצף של 1 כמספר הבתים הדרושים ואחריהם יבוא 0. לדוגמה, אם ברצוננו לקודד את המספר באמצעות שלושה בתים, הבית הראשון יחל ברצף 1110 ובכלליות יהיה מהצורה 1110xxxx (בהמשך יוסבר מהם הערכים הנוספים).
כל בית נוסף (קרי, הבית השני, השלישי והרביעי ברצף, אם קיימים) יחל ברצף 10 ובכלליות ייראה כך: 10xxxxxx.
כעת ברשותנו מספר בתים, בהם חלק מהסיביות כבר תפוסות בשל הכללים הקודמים וכן סיביות חופשיות (אותן סימנו ב-x בסעיפים הקודמים). נמיר את המספר לייצוג בינארי עם מספר סיביות כמספר הסיביות הפנויות ונמלא אותן במספר שקיבלנו.
הטבלה הבאה מסכמת את עקרונות הקידוד:
| טווח מספרים הקסדצימלי | ערך המספר הייצוגי בינארי | UTF-8 בינארי | הערות |
| --- | --- | --- | --- |
| 000000–00007F   128 ערכים  | 0zzzzzzz | 0zzzzzzz | ערכים המקבילים ל-ASCII, הסיבית המשמעותית ביותר כבויה. |
| 000000–00007F   128 ערכים  | שבעה z | שבעה z | ערכים המקבילים ל-ASCII, הסיבית המשמעותית ביותר כבויה. |
| 000080–0007FF   1920 ערכים  | 00000yyy yyzzzzzz | 110yyyyy 10zzzzzz | הבית הראשון מתחיל ברצף 110, שאר הבתים מתחילים ברצף 10. |
| 000080–0007FF   1920 ערכים  | שלושה y; שני y, שישה z | חמישה y; שישה z | הבית הראשון מתחיל ברצף 110, שאר הבתים מתחילים ברצף 10. |
| 000800–00FFFF   63488 ערכים  | xxxxyyyy yyzzzzzz | 1110xxxx 10yyyyyy 10zzzzzz | הבית הראשון מתחיל ברצף 1110, שאר הבתים מתחילים ברצף 10. |
| 000800–00FFFF   63488 ערכים  | ארבעה x,ארבעה y; שני y,שישה z | ארבעה x; שישה y; שישה z | הבית הראשון מתחיל ברצף 1110, שאר הבתים מתחילים ברצף 10. |
| 010000–10FFFF   1048576 ערכים  | 000wwwxx xxxxyyyy yyzzzzzz | 11110www 10xxxxxx 10yyyyyy 10zzzzzz | הבית הראשון מתחיל ברצף 11110, שאר הבתים מתחילים ברצף 10. |
| 010000–10FFFF   1048576 ערכים  | שלושה w, שני x; ארבעה x, ארבעה y; שני y, שישה z | שלושה w; שישה x; שישה y; שישה z | הבית הראשון מתחיל ברצף 11110, שאר הבתים מתחילים ברצף 10. |
לשם המחשה נקודד את האות העברית אל"ף (א'), סימנה ביוניקוד U+05D0, באמצעות UTF-8:
האות נמצאת בטווח האותיות שבין U+0080 ל-U+07FF ולכן תקודד על ידי שני בתים.
הבית הראשון יהיה מהצורה 110xxxxx (שני 1 משום שיש שני בתים, ואחריהם 0 כנדרש) והבית השני יהיה מהצורה 10xxxxxx (משום שהוא בית נוסף הוא מתחיל ברצף 10).
המספר המייצג את אל"ף הוא 0x05D0. אנו רואים שברשותנו 11 סיביות פנויות (נספור את סך ה-x בשני הבתים) ולכן נרשום את המספר בייצוג בינארי תוך שימוש ב-11 סיביות, נקבל: 101-1101-0000 (המקפים הם לשם בהירות הקריאה בלבד ואינם נדרשים).
נחדיר את המספר הבינארי לתוך הסיביות הפנויות. נצטרך לחלק את המספר לחמש סיביות ושש סיביות בצורה 10111-010000 (זהו אותו מספר, פשוט שינינו את החלוקה) ונקבל: 10010000 11010111.
התוצאה הסופית היא שני הבתים לעיל, אותם ניתן לבטא בנוחיות רבה בצורה ההקסדצימלית 0xD7 0x90, וכך מקודדת ב-UTF-8 האות אל"ף.
במקור, UTF-8 תמך גם בקידודו של תו באמצעות חמישה ואף שישה בתים. קידוד באמצעות שישה בתים מעניק מרחב של 31 סיביות חופשיות וכך ניתן לכסות את כל האזור 0x7FFFFFFF-0x00000000. בפועל, הוחלט שכל המספרים הייצוגיים של יוניקוד יישארו בטווח 0x10FFFF-0x000000, הדורש רק 21 סיביות, ולכן UTF-8 הוגבל על ידי RFC 3629 לייצוג באמצעות עד ארבעה בתים (המעניקים 21 סיביות פנויות).