Browsed by
תגית: encoding

Character Encoding

Character Encoding

מכירים את זה ש-?????? ואז äîùáø?

בטח שמכירים. כשמנסים לפתוח תוכן שמקודד בצורה מסויימת לפי קידוד שונה, יתקבל משהו בסגנון. בעבר זה היה קורה מדי פעם בגלישה לאתרים בעברית (כיום כמעט ולא). היום ניתקל בזה בעיקר כאשר ננסה לפתוח מסמכים שנכתבו בסביבת Windows במערכות מבוססות Unix, או כאשר נעביר לנגן mp3 קבצים עם עברית (לדוגמא).

אני אנסה בפוסט הקרוב להסביר מה זה קידוד, מהם סוגי הקידוד הנפוצים, ואיך אפשר להתמודד עם בעיות של קידוד לא תואם.

מה זה קידוד

קידוד זו היכולת לבטא תווים באמצעי מוסכם אחר. מורס, או ברייל, הם סוגים של קידוד – כלומר, הוסכם שהרצף נקודה-קו משמעותו התו 'A'. אין משהו מיוחד בצורה של נקודה וקו שמרמזים על A, זה פשוט עניין של הסכמה. תרגום של שפה לקידוד מעניק לנו את האפשרות להשתמש בה בכלים שונים. לדוגמא, באמצעות מורס אפשר להעביר מידע למרחקים, באמצעות ברייל ניתן להעביר מידע ע"י מישוש.

המחשב מתרגם כל תוכן למספרים. כדי שנוכל להציג תווים על המסך, צריך "להסביר" למחשב איזה מספר מייצג כל תו.

ASCII

עד תחילת שנות השישים לא היה אף סטנדרט אחיד לקידוד תוים. עד כדי כך, שלעיתים על אותו מחשב רצו מספר תוכנות שכל אחת התייחסה לתווים בצורה שונה – התוכנות לא יכלו לתקשר ביניהן. בשנת 1963 הוסכם על קידוד אחיד: ASCII, שזה: American Standard Code for Information Interchange.

קידוד ASCII מכיל 128 תווים (27). הנה חלק מהטבלה:

  • (במקומות #0-31 – תווי בקרה שכבר לא בשימוש).
  • #32 – תו ריק (רווח).
  • #48-57 – ספרות.
  • #65-90 – אותיות גדולות (A, B, C..).
  • #97-122 – אותיות קטנות (a, b, c..).

החסרון של ASCII שהוא… אמריקאי. הוא עונה על הצרכים של דוברי אנגלית, אבל הוא מוגבל רק ל- 128 תווים – אין לו מקום לתווים בעברית, סינית או פולינזית. בזמן שהוא יצא הוא עשה מהפכה בעולם המחשוב, ולראשונה היתה שפה אחידה שתוכנות יכלו ״לדבר״ ביניהן, אבל היום זה לא ממש מספיק.

ISO-8859

הפיתרון לבעיות של ה- ASCII, היה להוסיף ביט אחד.

[הסבר קצר: המחשב מתרגם כל מספר לבינארי – בסיס 2. כל ספרה נוספת בה משתמשים מצויינת בביט. 8 ביטים = בייט.

הערכים של ASCII הם בין 0 ל- 127, שזה בבינארית 1111111. אם נוסיף ביט, כלומר נשתמש בבייט שלם – נוכל להכפיל את טווח הערכים. 11111111 יהיה הערך המקסימלי – 255.]

קיבלנו 128 ״מקומות פנויים״ לתווים נוספים. יש תקן עבור כל שפה שיש בה תווים מיוחדים, והם מאוכלסים ב- 128 מקומות האלו. כאשר המחשב מקבל את רצף הבייטים אותו הוא הולך לפענח לצורך הצגת תגים על המסך, הוא צריך לדעת את שם התקן כך שיוכל להשתמש בטבלה של השפה המתאימה.

מי שאחראי על התקינה הוא ISO, שזה International Organization for Standardization. זהו גוף שיוצר תקנים עבור כל דבר – ממידות נעליים, רמזורים ועד לכוסות לטעימת יין. התקן לקידוד לשפות שונות נקרא ISO-8859 באופן כללי, עם מספר נוסף שמציין את השפה הספציפית. ISO-8859-8 הוא התקן לקידוד התווים בעברית.

מיקרוסופט אימצו את התקן, ויצרו קידוד מקביל עבור כל שפה. לדוגמא הקידוד לעברית נקרא Windows-1255.

החסרונות של ISO-8859-x:

  • לא ניתן להשתמש באותו מסמך ביותר מקידוד אחד. כל מסמך יתורגם בצורה אחידה לפי קידוד ספציפי. ניתן לכתוב באנגלית + שפה נוספת וזהו.
  • התוכנה צריכה לדעת מראש במה הטקסט מקודד – האם מדובר בלטינית (ISO-8859-1), או ביוונית (ISO-8859-7). ניתן לבצע זיהוי אוטומטי, שמנסה לפענח חלק מהתווים לפי קידוד אחד ובודק אם זה יוצר רצף הגיוני, אבל זה לא תמיד עובד.

תווי כל העולם התאחדו

בגלל הבעיות הנ״ל, בסוף שנות ה- 80 הגיעו למסקנה שחייבים קידוד אחד עבור כל התווים, וכך נולד ה- Unicode.

ה- 256 תווים ראשונים זהים לקידוד ISO-8859-1, מה שאומר 128 תווי ASCII, ו- 128 תווי לטינית.

אחריהם יש… הכל. unicode מכיל כל תו קיים: עברית, יוונית או הירוגליפים מצריים – טבלה ענקית בה ממופים כל התווים. את הטבלה הזו מחלקים למישורים – planes, כל מישור מכיל 65536 תווים (216). במישור הראשון יש את התווים הנפוצים ביותר (הוא נקרא BMP – Basic Multilingual Plane) ואחריו 16 מישורים נוספים. בחשבון פשוט, קידוד unicode יכול להכיל 1,114,112 תווים (17 כפול 216).

אבל רק להמציא את הטבלה זה לא מספיק. המחשב בסופו של דבר מקבל רצף של מספרים והוא צריך לדעת איך לחלק אותם – כמה מספרים (או בייטים) יוצרים תו אחד. הגישה הנאיבית תהיה לבדוק כמה בייטים צריך כדי לייצג את המספר הגדול ביותר, וזה יהיה מספר הבייטים עבור כל תו. הבעיה היא שזה בזבוז – אם נסתכל על התווים הראשונים – שהם הכי שימושיים – מספיק בייט אחד לייצג אותם. אם נשתמש בגישה כזו נפח המידע שנצטרך יהיה פי 4.

UTF-8 בא לפתור את הבעיה הזו, Unicode Transformation Format – זהו קידוד מבוסס Unicode. הוא בנוי כך שלפי מספר ביטים בתחילת כל תו ניתן לדעת כמה בייטים לקרוא עבורו. לדוגמא לתווי ה- ASCII שנמצאים בהתחלה (128 הראשונים) – והם גם השימושיים ביותר – נוכל להשתמש בבייט אחד, בצורה הזו: 0xxxxxxx. ככל שמתקדמים בטבלה נצטרך לכל תו יותר בייטים. כאן יש הסבר על איך זה בנוי.

כיום UTF-8 פופולארי ברוב אתרי האינטרנט, ובמערכות הפעלה מבוססות Unix. הוא מאפשר קידוד אחד לכל התווים, בצורה יעילה, והוא מאפשר תאימות אחורה – כל עוד המסמך מכיל רק תווי ASCII הם ייראו אותו דבר.

קוד

כדי לפתור את בעיית פתיחת מסמכים שנשמרו ב- Windows בסביבת Unix – נשתמש בקוד הבא (python):

#!/usr/bin/python
 
import codecs, sys
 
if len(sys.argv) > 1:
    path = sys.argv[1]
else:
    print "arg not found. Run encode.py "
    sys.exit()
# open with Windows format
sourceFile = codecs.open(path, "r", "iso-8859-8")
# save decoded content
contents = sourceFile.read()
# close file so we can re-open it for writing
sourceFile.close()
# open with utf-8 format
targetFile = codecs.open(path, "w", "utf-8")
targetFile.write(contents)
targetFile.close()

זו המקבילה בקוד לפתרון של פתח-בפנקס-רשימות-ושמור-בפורמט-אחר. נפתח את הקובץ כשאנחנו מתייחסים אליו כפורמט iso-8859. נשמור את התוכן, ואז נפתח אותו מחדש בפורמט utf-8 ונכתוב לתוכו את התוכן.

בנוסף, ספריית python שימושית: Chardet. כשמה, היא מזהה את הקידוד בו נכתב הקובץ. בקטע קוד הנ״ל אני מניח שהקידוד של הקובץ הוא ISO-8859-8 (כי זה ידוע לי), אבל אפשר להשתמש ב- Chardet כדי לזהות אוטומטית את הקידוד, וכך הקוד יעבוד גם על עוד קידודים (=שפות).

סיכום

ישנם 3 קידודים בהם ייתכן וניתקל: ASCII, ISO-8859-x, UTF-8. ההבדלים ביניהם יצוצו רק כאשר נשתמש בתווים שהם לא אנגלית/מספרים.

נראה שבעתיד כולם יעברו להשתמש ב- Unicode. גם אם UTF-8 לא נתמך רשמית ב- Windows ברמת מערכת ההפעלה, לא מעט תוכנות כבר משתמשות בו כברירת מחדל.

עד אז, äîùáø.