Loading AI tools
מוויקיפדיה, האנציקלופדיה החופשית
UTF-8 (ראשי תיבות של 8-bit Unicode Transformation Format או 8-bit UCS Transformation Format) הוא קידוד תווים באורך משתנה ליוניקוד, שנוצר על ידי רוב פייק וקן תומפסון. ניתן לקודד בו כל תו המצוי בתקן יוניקוד על ידי שימוש באחד עד ארבעה בתים, תלוי בתו. הקידוד ב-UTF-8 מעניק את כל יתרונות השימוש בקידוד ליוניקוד ומוסיף עליהם, בין היתר, גם חיסכון בזיכרון, עמידות בפני איבוד או השחתת בתים ותאימות לאחור ל-ASCII. ה-IETF מעדיף בבירור את UTF-8 ומחייב כל פרוטוקול אינטרנט לתמוך בו, וכן קונסורציום הדואר האלקטרוני, ה-IMC, ממליץ שכל תוכנת דואר אלקטרוני תוכל להציג וליצור דואר באמצעות UTF-8.
שיטת הקידוד המוכרת כ-UTF-8 הומצאה על ידי קן תומפסון בערב 2 בספטמבר 1992. תומפסון כתב את רעיונו על מצעית בעת ששהה במזנון מהיר בניו ג'רזי עם רוב פייק. ביום שלאחר מכן, פייק ותומפסון מימשו את רעיונם והפכו את מערכת ההפעלה Plan9 של מעבדות בל למערכת ההפעלה הראשונה בעולם המשתמשת בקידוד. UTF-8 הוצג רשמית לראשונה בכנס USENIX בסן דייגו שנערך ב-25 - 29 בינואר 1993.
מאז פורסמו מספר הגדרות ל-UTF-8, בהן:
הגדרות אלו מיושנות ואינן בשימוש יותר. במקומן קיימות ההגדרות הבאות:
שלוש ההגדרות מסכימות על מנגנון הקידוד, וההבדלים ביניהן נסובים בעיקר סביב נושאים כגון טווח המספרים המייצגים המותרים לשימוש ביוניקוד וכיצד יש לטפל בקלט שגוי.
פרויקט יוניקוד החל כחלק ממאמץ ליצור מערכת תווים אחידה בינלאומית (באנגלית: UCS - Unified Character Set). בפשטנות גדולה ניתן לומר שיוניקוד הוא טבלה גדולה של תווים הממפה כל תו למספר המייצג אותו. יוניקוד אינו מפרט כיצד יש לייצג מספר זה במחשב. דרושה שיטה שבאמצעותה ניקח את המספר המייצג את התו ונשמור אותו במחשב בתור בית (או רצף של בתים). לשיטה זו אנו קוראים "קידוד תווים".
UTF-8 הוא קידוד תווים, הוא מורה לנו כיצד יש לקחת את המספר הייצוגי ולשמור אותו במחשב (וכיצד יש לקרוא מספרים השמורים במחשב ולהמירם למספרים ייצוגיים שלאחר מכן נוכל להמיר לתווים). אם ברשותנו טקסט ואנו מעוניינים להכניסו למחשב באמצעות קידוד יוניקוד, תחילה נחליף כל תו בטקסט למספרו הייצוגי לפי טבלת יוניקוד. כעת ברשותנו רצף של מספרים, באמצעות UTF-8 נשמור את המספרים הללו במחשב. UTF-8 מבוסס על יוניקוד בכך ששיטת השמירה שלו מבוססת על המספרים הייצוגיים שנקבעו ביוניקוד.
בעוד שקיים מיפוי אחד של תווים למספרים ייצוגיים בשם יוניקוד, קיימות דרכים רבות לשמור מספרים אלה במחשב, קרי, קיימים קידודי תווים רבים ליוניקוד. בהם UCS-2 ו-UCS-4 הפשוטים המורים לשמור את המספר באמצעות 2 או 4 בתים בהתאמה (קידודים אלה אינם בשימוש, שני בתים אינם מספיקים יותר לכל תווי יוניקוד ו-UCS-4 הפך ל-UTF-32) וכן גם קידודים מתוחכמים יותר כמו UTF-8 ו-UTF-16.
הקידוד ב-UTF-8 הוא תלוי תו, או נכון יותר תלוי במספר המייצג את התו בתקן היוניקוד. לכל תו ברפרטואר התווים של יוניקוד יש מספר המייצג אותו. קיימים תווים שמסיבות של תאימות או סיבות אחרות חוזרים מספר פעמים ברפטואר אך לכל אחד מהם מספר שונה. כל מספר מייצג תו אחד בלבד ולכן ניתן, ואולי אף עדיף, לדבר על התווים דרך מספריהם הייצוגיים ולא דרך שמותיהם, כדי למנוע בלבול. נהוג לרשום את המספרים המייצגים את התווים בצורה הקסדצימלית בשל קלות ההמרה מצורה זו לצורה הבינארית שהיא הצורה בה נכתבים המספרים למחשב. נהוג גם, כאשר מדברים על תווים או המספרים המייצגים אותם, לנקוט בסימונים מיוחדים המבהירים שמדובר ביוניקוד:
כאשר נאמר U+05D0 נתכוון בעצם לאות אל"ף (א') כפי שהיא מוגדרת בתקן היוניקוד. כאשר נאמר 0x05D0 נתכוון בעצם למספר מסוים (שבמקרה מייצג ביוניקוד את האות אל"ף). משום שמדובר אך ורק במספר, נוכל לכותבו בכל צורה שנחפוץ כל עוד ערכו זהה. נוכל לרשום למשל גם 0x000005D0, או 1488, שהוא ערכו של המספר בבסיס העשרוני (ראו בסיס ספירה) – ממש כפי שאין הבדל אם נרשום 2 או 2.0 או 002 מבחינת ערך המספר.
הקידוד ב-UTF-8 פועל לפי מספר עקרונות פשוטים:
הטבלה הבאה מסכמת את עקרונות הקידוד:
טווח מספרים הקסדצימלי |
ערך המספר הייצוגי בינארי |
UTF-8 בינארי |
הערות |
---|---|---|---|
000000–00007F 128 ערכים |
0zzzzzzz | 0zzzzzzz | ערכים המקבילים ל-ASCII, הסיבית המשמעותית ביותר כבויה. |
שבעה z | שבעה z | ||
000080–0007FF 1920 ערכים |
00000yyy yyzzzzzz | 110yyyyy 10zzzzzz | הבית הראשון מתחיל ברצף 110, שאר הבתים מתחילים ברצף 10. |
שלושה y; שני y, שישה z | חמישה y; שישה z | ||
000800–00FFFF 63488 ערכים |
xxxxyyyy yyzzzzzz | 1110xxxx 10yyyyyy 10zzzzzz | הבית הראשון מתחיל ברצף 1110, שאר הבתים מתחילים ברצף 10. |
ארבעה x,ארבעה y; שני y,שישה z | ארבעה x; שישה y; שישה z | ||
010000–10FFFF 1048576 ערכים |
000wwwxx xxxxyyyy yyzzzzzz | 11110www 10xxxxxx 10yyyyyy 10zzzzzz | הבית הראשון מתחיל ברצף 11110, שאר הבתים מתחילים ברצף 10. |
שלושה w, שני x; ארבעה x, ארבעה y; שני y, שישה z | שלושה w; שישה x; שישה y; שישה z |
לשם המחשה נקודד את האות העברית אל"ף (א'), סימנה ביוניקוד U+05D0, באמצעות UTF-8:
במקור, UTF-8 תמך גם בקידודו של תו באמצעות חמישה ואף שישה בתים. קידוד באמצעות שישה בתים מעניק מרחב של 31 סיביות חופשיות וכך ניתן לכסות את כל האזור 0x7FFFFFFF-0x00000000. בפועל, הוחלט שכל המספרים הייצוגיים של יוניקוד יישארו בטווח 0x10FFFF-0x000000, הדורש רק 21 סיביות, ולכן UTF-8 הוגבל על ידי RFC 3629 לייצוג באמצעות עד ארבעה בתים (המעניקים 21 סיביות פנויות).
הקידוד באמצעות מספר משתנה של בתים ורצפי הסיביות בתחילת כל בית, אם הוא חלק ממספר בתים המייצגים תו בודד, הופך את UTF-8 לאמין, עמיד בפני תקלות שונות וחסכוני.
חוקי הקידוד דורשים שיתקיימו התנאים הבאים:
כתוצאה מכך, לא ניתן להתבלבל בין בית המייצג תו ASCII (בית בודד המייצג תו בודד) לבין בית שהוא חלק ממספר בתים המייצגים יחדיו תו אחד (זאת משום שבמקרה הראשון הסיבית המשמעותית ביותר היא 0 ובמקרה השני תהיה הסיבית המשמעותית ביותר 1). באופן כללי יותר, החוקים הנ"ל מבטיחים שלא יכול להתקיים מצב בו רצף בתים המייצג תו מסוים יוכל בתוך רצף בתים גדול יותר המייצג תו אחר. המשמעות של העניין היא שגם אם נסתכל על חלקים מהקידוד, לעולם לא נוכל לפרש אותם כתווים אחרים פרט לתווים שהם יועדו להיות מלכתחילה. לא ייתכן שמתוך ארבעה בתים המייצגים תו, אם נסתכל רק על שניים נוכל לחשוב בטעות שמדובר בתו אחר. כעת ניתן להשתמש באלגוריתמי חיפוש המסתמכים על הבתים מהם מורכב הטקסט, כדי לחפש מילים או ביטויים בטקסט בצורה יעילה. נוסף על כך, אם בית אחד הושחת או אבד בנסיבות כלשהן (למשל, במהלך העברה ברשת), רק תו אחד ייפגם, שכן ברגע שנגיע לתו הבא נבחין שמתחיל רצף חדש של בתים ולכן תו חדש. בשיטות אחרות, איבוד בית אחד יכול להוביל להשחתה של הטקסט כולו.
מבחינה סטטיסטית, אם רצף של בתים עבר את בדיקות ה-UTF-8 והתברר כרצף שעלול לייצג תו או מספר תווים ב-UTF-8, נראה שאכן מדובר בקידוד UTF-8. תכונה זו עוזרת בכך שהיא מונעת מצב בו תוכנה תטעה לחשוב שטקסט מסוים קודד ב-UTF-8, תנסה להציגו כך ויתקבל טקסט לא קריא. תופעה זו שכיחה מאוד בקרב קידודי ISO 8859, שכן לא ניתן להבדיל בין קידוד אחד במשפחה לשני. גולשי אינטרנט ישראלים רבים נתקלו בתופעה של דף המציג אותיות מערב-אירופאיות במקום האותיות העבריות משום שהדפדפן טעה לחשוב שהדף מקודד ב-ISO-8859-1 במקום ISO-8859-8 (שהוא הקידוד המכיל את האותיות העבריות במשפחה).
תוספת הסיביות בתחילת כל רצף בתים המייצגים מותירה פחות סיביות לשם ייצוג המספר ולכן דורשת לעיתים בית נוסף. 128 התווים הראשונים צורכים רק בית אחד, תווים אלו הם תווי ASCII ואלו הם התווים בהם נעשה השימוש הנרחב ביותר בכל הטקסטים בעולם (כל שיטות הקידוד האחרות ליוניקוד יקודדו תווים אלה ביותר מבית אחד). 1920 התווים הבאים צורכים שני בתים לקידוד, אלה כוללים את תווי האלפבית לטיני עם הסימנים הדיאקריטיים, האלפבית היווני, האלפבית הקירילי, הקופטית, הארמנית, האלפבית העברי והאלפבית הערבי. שאר התווים במשטח הרב-לשוני הבסיסי (65,536 התווים הראשונים) משתמשים בשלושה בתים, ושאר התווים הנתמכים ביוניקוד משתמשים בארבעה בתים לקידוד. ככל ש-UTF-8 צורך יותר בתים לקידוד התו, אנו שמים לב שמדובר בתו ששכיחותו בטקסטים באופן כללי נמוכה יותר. התווים שאינם במשטח הרב-לשוני הבסיסי הם תווים שכמעט ולא, או כלל לא, היו קידודים שתמכו בהם קודם לכן והשימוש בהם הוא מזערי (מדובר בתווים מוזיקליים, סימנים מתמטיים ואותיות בשפות היסטוריות). טקסט שנכתב כולו באנגלית יתפוס את אותה כמות המקום בזיכרון כפי שהיה תופס לו קודד בשיטות הקידוד הישנות, וטקסט שנכתב בשפה שכיחה, שאינה אנגלית, יתפוס עד פי שניים מהמקום שהיה תופס לו קודד בשיטות הישנות. טקסט המשלב בתוכו מספר שפות שכיחות יתפוס כמות מקום זהה לטקסט הכתוב רק בשפה אחת שכיחה, אך לא ניתן להשוות לכמות הזיכרון שהיה תופס לו היה נכתב בשיטות הקידוד הישנות, משום שאותן שיטות כלל לא אפשרו הצגה של מספר שפות (שאחת מהן אינה אנגלית) באותו הטקסט.
בשעת קידוד, מקודד ה-UTF-8 ממיר את התו המבוקש למספר לפי טבלת יוניקוד ואז, תלוי בערכו של אותו מספר, ממיר אותו למספר הבתים הנדרש. מפענח UTF-8 הקורא קטע שקודד קודם לכן קורא את הבתים, על-פי הסימונים מחליט כמה בתים עליו לקרוא לשם קבלת תו בודד, מוציא מבתים אלה את המספר ואז הולך לטבלת יוניקוד ורושם את התו המתאים.
אם ברצוננו לקודד את התו U+000A שהוא תו הזנת השורה, עלינו רק ללכת לפי אלגוריתם הקידוד ומיד נגלה שכל שעלינו לעשות הוא לכתוב בבית אחד את המספר 0x000A. אם מפענח UTF-8 יתקל בבית 0x000A, מיד ידע שמדובר בבית בודד המייצג תו בודד (הסיבית המשמעותית ביותר היא 0) ואז יבדוק מהו התו U+000A. נשאלת השאלה מה יקרה אם מפענח ה-UTF-8 יתקל באחד מרצפי הבתים הבאים:
נבחן את האפשרות הראשונה, 0xC0 0x8A, ההמרה הבינארית היא 10001010 11000000. הסיביות המודגשות הן הסיביות המכילות את המספר בהצגתו הבינארית, המספר הוא 0x000A ומייצג את התו U+000A ביוניקוד. הליך פיענוח דומה של שתי האפשרויות האחרות יביא לתוצאה זהה. נראה אם כן שניתן להציג תווים מסוימים ביותר מדרך אחת. לכאורה ניתן להציג תווים בדרך המומלצת (והחסכונית) או להציג אותם על ידי שימוש ביותר בתים.
הצגתו של תו על ידי יותר בתים ממה שצריך מכונה הצגתו ב"צורה הארוכה" (Overlong Form). בעבר נעשה שימוש זדוני באפשרות של הצגת תווים בצורתם הארוכה לשם עקיפת מנגנוני אבטחה שונים. תוכנות האבטחה לא פענחו את הקוד לפני הבדיקה אלא ביצעו את הבדיקה ישירות על הבתים המקודדים תוך כדי הסתמכות על אלגוריתם הקידוד המוכר ועל העובדה שכל תו מקודד בצורה הקצרה ביותר. בשיטה זו נעקפו מנגנוני הביטחון של שרתי IIS של מיקרוסופט. השימוש בצורה הארוכה של תווים מנע מתוכנת האבטחה למצוא אותם. עקב כך השימוש בצורות ארוכות נאסר על ידי סטנדרט RFC 3629.
הסטנדרטים המגדירים את UTF-8 אינם מגדירים תגובה אחידה לאופן בו צריך מפענח UTF-8 לנהוג אם הוא נתקל בקלט לא תקין (למשל בית המצהיר על התחלה של רצף של ארבעה בתים ולאחריו בית אחד בלבד, או למשל צורה ארוכה עליה נכתב קודם לכן). קיימות מספר אפשרויות לפיהן יכול המפענח לנהוג:
קיימת אפשרות גם שהמפענח ינהג בצורה שונה כאשר הוא נתקל בסוגי קלטים לא תקינים שונים.
סטנדרט RFC 3629 דורש רק שמפענחי UTF-8 לא יפענחו "צורות ארוכות". סטנדרט היוניקוד דורש ש"כל מפענח יוניקוד יתייחס לכל קטע קוד שגוי כשגיאה. זה יבטיח שהוא לא יפרש או יפלוט רצף קוד שגוי".
הטיפול בקלטים לא תקינים חשוב מטעמי אבטחת מידע, כפי שראינו לגבי צורות ארוכות. ישנן שתי אפשרויות לטפל בקלט לא תקין ולשמור על ביטחון המידע: האפשרות הראשונה היא לפענח את קידוד UTF-8 לפני שעושים בדיקות כלשהן (ואז לבצע את הבדיקות על הטקסט המפוענח). האפשרות השנייה היא להשתמש במפענח שבמקרה של קלט לא תקין מוציא הודעת שגיאה או טקסט שהאפליקציה מחשיבה כבלתי מזיק. אפשרות נוספת היא כלל לא לפענח את קידוד UTF-8, אך זה מחייב את התוכנה אליה מעבירים את הטקסט המקודד לטפל בעצמה בקלט לא תקין.
חשיבות נוספת לזיהוי קלטים לא תקינים ודרך הטיפול בהם היא לשם טיפול במקרים של איבוד או השחתה של בתים. אם בית הושחת או אבד והמערכת מזהה מספר לא נכון של בתים המייצגים תו, ביכולתה למזער את הנזק לפגיעה בתו זה בלבד. התעלמות מהבעיה והנחה שכל הבתים מופיעים ללא בדיקה שאכן כל אחד מהבתים העוקבים תואם את הדגם, עלולה במקרה של בית אחד חסר להביא לקריסת הפענוח כולו והשחתה של הטקסט (בניגוד להשחתה של תו אחד).
UTF-8 הוא קידוד ברירת המחדל במערכות יוניקס ולינוקס.
שפת התכנות Java תומכת בקריאה וכתיבה של מחרוזות המקודדות ב-UTF-8, דרך המחלקות InputStreamReader ו-OutputStreamWriter. מאידך, למטרות של סיריאליזציה של אובייקטים, שימוש ב-Java Native Interface ולשם הטמעת קבועים בקובצי class, משתמשת Java בגרסה קצת שונה של UTF-8 המכונה UTF-8 משופר (modified UTF-8). ישנם שני הבדלים בין UTF-8 התקני לזה המשופר. הראשון שבהם הוא שתו ה-NUL, שסימונו ביוניקוד U+0000, מקודד באמצעות שני בתים במקום בית אחד בצורה: 10000000 11000000. שינוי זה מבטיח שבעת קידוד המחרוזת לא יוטמעו בה תווי NUL וכך נפתרת בעיית עיבוד המחרוזות בשפות כמו שפת C המשתמשות בתו ה-NUL כסימון לסיום מחרוזת וכל תו NUL מוטמע יביא לחיתוך המחרוזת בטרם עת. ההבדל השני הוא בצורת קידודם של תווים מחוץ למשטח הרב-לשוני הבסיסי. ב-UTF-8 התקני, מקודדים תווים אלה באמצעות ארבעה בתים. ב-UTF-8 המשופר, תווים אלה מומרים קודם כל לצורה של זוגות ממלאי מקום (surrogate pairs), כמו ב-UTF-16 ואז כל אחד מבני הזוג מקודד לבדו והקידודים נכתבים ברצף, כמו ב-CESU-8. הסיבה להבדל זה מעודנת יותר. ב-Java, אורכו של משתנה מסוג תו הוא 16 סיביות. מסיבה זו, חלק מתווי יוניקוד דורשים שימוש בשני משתנים מסוג תו לשם ייצוג הולם. תכונה זו של השפה אינה תואמת את ההתקדמות ביוניקוד וההחלטה לפרוץ את גבולות המרחב הרב-לשוני הבסיסי, אך היא חיונית לשם ביצועים ולשם תאימות לאחור ולכן לא סביר שתשתנה. השימוש ב-UTF-8 משופר מבטיח שניתן יהיה לפענח מחרוזות מקודדות על ידי פיענוח של יחידת קוד של UTF-16 אחת בכל פעם ולא על ידי פיענוח מספר ייצוגי אחד של יוניקוד בכל פעם. השימוש ב-UTF-8 משופר גורם לכך שקידודם של תווים הדורשים ארבעה בתים כאשר משתמשים בצורה התקנית של UTF-8, דורש ב-UTF-8 המשופר שימוש בשישה בתים.
מערכת ההפעלה, Mac OS X, המיועדת למחשבי מקינטוש, מקודדת את שמות הקבצים במערכת הקבצים שלה על ידי שימוש ב-UTF-8 המותאם ליוניקוד מופרד קנונית. לעיתים מתייחסים לגרסה זו של UTF-8 כאל UTF-8-MAC. ביוניקוד, אם ברצוננו לייצג למשל את האות Ä (האות האנגלית הגדולה A עם שתי נקודות מעליה), נוכל להשתמש בתו היוניקוד U+00C4, שהוא בדיוק האות Ä. לחלופין, נוכל גם להשתמש בתו U+0041 שהוא התו A (האות האנגלית הגדולה A) ומיד לאחריו לשים את התו U+0308 שהוא הסימן הדיאקריטי שתי נקודות מעל לאות. בעיקרון תקן היוניקוד קובע חוקים לשילוב סימנים דיאקריטיים. קיימים בתקן תווים מיוחדים הנקראים תווים משלבים (combining characters). כתיבת אות ולאחריה תווים משלבים אמורים להוביל להצגת האות עם הניקוד. מטעמי תאימות לאחור ומסיבות אחרות, חלק מהאותיות עם הניקוד קיימות כתו נפרד ביוניקוד. תווים אלה נקראים תווים מורכבים מראש (precomposed characters) והתקן קובע גם לאילו תווים הם שקולים. יוניקוד מופרד, או מפורק, קנונית הוא יוניקוד שבו נאסר השימוש בתווים מורכבים מראש ולכן חייבים להשתמש בשילוב של אותיות וסימנים דיאקריטיים בכל מקום שבו נחוץ תו עם סימן דיאקריטי. השימוש ביוניקוד מופרד מקל רבות על הליכי מיון אך יוצר בלבול בקרב תוכנות המניחות שתווים מורכבים הם הצורה השכיחה ושילוב של תווים משלבים נעשה רק עבור צירופים מיוחדים. (זוהי דוגמה להגוון ה-NFD לנירמול טקסט). קיים דיון נרחב בנושא במסמך Apple Computer's Q&A 1173.
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.