BookTranslator
BookTranslator

תיקון קידוד כתוביות SRT בלי לאבד את הטקסט המקורי

אבחנו טקסט SRT משובש, הבחינו בין שגיאות פענוח לתווים שאבדו, וצרו עותק UTF-8 נפרד בעזרת כלי Python בטוח ודוגמאות שניתנות לשחזור.

BookTranslator

BookTranslator Team

קריאה של 10 דקות

אם כתוביות ה-SRT שלכם מציגות café במקום café, אל תשמרו מיד את הקובץ כ-UTF-8. תחילה שמרו עותק ללא מגע של הבייטים המקוריים שלו, זהו פענוח שמפיק את המילים הנכונות, וכתבו את הטקסט המאומת לקובץ נפרד. שמירת התווים השגויים בקידוד חדש רק מקבעת את הטעות.

ההבחנה החשובה היא קידוד תקין לעומת טקסט נכון. בניסוי שני מקטעי הכתוביות המקורי שלהלן, קובץ פגום אחד עובר בדיקת UTF-8 קפדנית ואינו מכיל תווים חלופיים. ובכל זאת, הטקסט בצרפתית עדיין שגוי. קובץ אחר עובר את אותה בדיקה לאחר ששישה תווים מקוריים הוחלפו ב- �.

מדריך זה מספק כלי Python מקומי לבדיקה ולהמרה, קובצי מקור להורדה ומבחן שניתן לשחזור. הוא מתמקד באבחון ברמת הקובץ ובהמרה מפורשת — ולא בזיהוי קידוד אוטומטי, בסנכרון וידאו או בהבטחה לשחזר אותיות חסרות.

ראשית, זהו מה באמת שבור

הסיומת .srt מזהה פורמט כתוביות, ולא קידוד מובטח. קובץ SRT כולל מספרי מקטעים, חותמות זמן, טקסט ומפרידים; תיעוד פורמט ה-SRT של ספריית הקונגרס מגדיר אותו כטקסט פשוט ללא תקן קידוד תווים אחיד.

השתמשו בתסמין הגלוי כסיבה לבדיקה, ולא כאבחנה בפני עצמה:

מה שרואיםמה לבדוקהצעד הבא המתאים
סימני הטעמה או סמלים נראים משובשים ביישום מסויםהאם פתיחה מחדש של הקובץ המקורי ללא שינוי, באמצעות קידוד המקור הידוע, מפיקה את הטקסט הנכון?אם כן, השתמשו בפענוח מפורש זה לפני ייצוא עותק חדש.
café נשאר בקובץ שנקרא כהלכה כ-UTF-8האם קובץ UTF-8 נקרא בעבר בטעות בקידוד אחר ונשמר מחדש?חזרו לבייטים המקוריים, או בדקו את היסטוריית ההמרה המדויקת. שמירה נוספת ב-UTF-8 אינה מהווה תיקון.
� מופיע במקום שבו אמורה להיות אות או סמלהאם U+FFFD נשמר בפועל בקובץ, או שהיישום הנוכחי מחדיר אותו בעת הצגת בייטים שלא ניתן לפענח?בדקו את קובץ המקור ללא מגע יד. תו חלופי שנשמר אינו מאפשר לזהות את התו המקורי.
מופיעים מרובעים בנגן, אך תצוגת טקסט מהימנה מציגה את התווים המיועדיםהאם נקודות הקוד הבסיסיות תקינות? האם הנגן טוען את אותו הקובץ?בדקו את פענוח הקידוד של הנגן, את כיסוי הגופנים או את הגדרות הרינדור לפני שאתם משנים את הקובץ.

תווים והצורות המוצגות שלהם הם שני דברים שונים. ההסבר על Unicode של Python מבדיל בין נקודות קוד (code points) לבין גליפים המרונדרים על ידי הגופן. טקסט תקין בעורך טקסט הופך בעיה בצד הנגן לסבירה; אין בכך הוכחה שהתקנת גופן מסוים תפתור אותה. אף גופן או נגן לא נבדקו עבור מאמר זה.

גבו את הבייטים, ולאחר מכן בדקו את הפענוח

הורידו את subtitle_encoding.py והניחו אותו לצד קובץ ה-SRT שברצונכם לבדוק. פקודות אלו דורשות התקנה קיימת של Python 3 ואינן מצריכות חבילות נוספות. הבדיקות המקומיות כאן בוצעו באמצעות Python 3.14.3 ב-macOS. אם בהתקנת ה-Windows שלכם נעשה שימוש ב-Python launcher, החליפו את py -3 ב- python3; סביבה זו לא נבדקה כאן.

פתחו מסוף (terminal) באותה תיקייה. בדוגמאות אלו, החליפו את input.srt בשם הקובץ האמיתי שלכם. שמרו על מירכאות סביב נתיבים המכילים רווחים.

צרו עותק ללא מגע יד

python3 subtitle_encoding.py backup "input.srt" "original-bytes.srt"

נתיב היעד אינו יכול להיות קיים מראש. הכלי מעתיק בייטים מבלי לפענח אותם, קורא את העותק בחזרה ומדווח על גיבוב ה-SHA-256 שלו. הוא גם מסרב לקבל את נתיב המקור כיעד. שמרו גיבוי זה גם לאחר יצירת כתוביות שניתן להשתמש בהן.

בדיקת UTF-8 מבלי לשמור דבר

python3 subtitle_encoding.py inspect "original-bytes.srt"

הדוח כולל את strict_utf8, utf8_bom, הקידוד שנבחר, ואם הפענוח מצליח—תצוגה מקדימה של הטקסט ו- replacement_characters . תצוגת ברירת המחדל לטקסט משתמשת ב- utf-8-sig, שמטפל בחתימת UTF-8 פותחת.

  • strict_utf8: false מציין שהבייטים נכשלים בבדיקת UTF-8. הוא אינו מציין איזה קידוד אחר הוא הנכון.
  • strict_utf8: true מציין שניתן לפענח אותם כ-UTF-8. אין זה אומר שהמילים עצמן נכונות.
  • ספירת החלפות שאינה אפס פירושה שהפענוח שנבחר ייצר תווי U+FFFD. בדקו אותם היטב לפני יצירת קובץ חדש.

הבדיקה מדפיסה פלט JSON בטוח ל-ASCII כדי שגופן המסוף לא יוכל להסוות את זהות התווים: \u00e9 פירושו é, ו- \ufffd מייצג את תו ההחלפה. כדי לבחון שורה חשודה בפירוט, בקשו את מספר השורה הפיזי שלה — ולא את מספר הכתובית:

python3 subtitle_encoding.py inspect "original-bytes.srt" --encoding cp1252 --line 3

זוהי בדיקת קריאה בלבד עבור Windows-1252, המקודד cp1252 של Python. השתמשו בו כאשר הגדרות הייצוא או היסטוריית המקור תומכות בבחירה זו, ולא מפני שדוגמה זו במקרה השתמשה בצרפתית. דוח השורה מציין את שמו של כל תו ומציג את נקודת הקוד שלו; U+20AC הוא סימן האירו.

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

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

"ANSI" אינו מונח מדויק מספיק לבחירת מקודד המקור. כמו כן, Windows-1252 ו-Latin-1 אינם ניתנים להחלפה זה בזה. בניסוי שסופק, הבייט הבודד 80 מפוענח כ- € תחת cp1252, אך כתו בקרה U+0080 תחת latin-1. שתי הפעולות מצליחות. רק מקור ידוע יכול ללמד אותנו מה הייתה הכוונה המקורית.

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

המרה מתבצעת רק לאחר שטקסט המקור קריא

עבור מקור שאושר בוודאות כ-Windows-1252, צרו קובץ UTF-8 נפרד:

python3 subtitle_encoding.py convert "original-bytes.srt" "repaired-utf8.srt" --from-encoding cp1252
python3 subtitle_encoding.py inspect "repaired-utf8.srt"

הממיר מפענח את המקור המלא באופן קפדני (strict), מקודד את הטקסט הזה כ-UTF-8, מוודא שפענוח הפלט מניב בדיוק את אותו הטקסט, וקורא חזרה את הבתים שנכתבו. הוא אינו משנה מספרי כתוביות, חותמות זמן, דיאלוגים, תגיות או סיומי שורות. רצף הבתים החדש עשוי להיות שונה אף שהטקסט המפוענח נותר זהה לחלוטין.

הוא מסרב במכוון ל:

  • לדרוס קובץ יעד קיים;
  • להמשיך מעבר לשגיאת פענוח קפדנית; או
  • לכתוב טקסט המכיל את התו U+FFFD, גם אם תו זה הופיע במכוון.

המגבלה האחרונה שמרנית במכוון: כלי זה אינו יכול לקבוע מה תו החלפה אמור היה לייצג. הסרתו רק כדי שהפקודה תצליח תמחוק ראיות במקום לשחזר את הטקסט. ה- תיעוד של מנהלי השגיאות ב-Python מסביר מדוע replace ו- ignore שונים מפענוח קפדני: הם מחליפים או משמיטים נתונים בעייתיים. לאף אחד מהם אין מקום בשלב המרה זה.

אם מתרחשת שגיאת קלט/פלט (I/O), אל תשתמשו בפלט שנכשל. ייתכן שיישאר קובץ חדש חלקי; שמרו על המקור והשתמשו בשם יעד חדש בניסיון הבא. התנהגות הכלי המלאה ואופן השימוש בו מפורטים ב- README להורדה.

מה לגבי UTF-8 עם BOM?

BOM של UTF-8 הוא רצף בתים פותח מסוג EF BB BF. המקודד utf-8-sig של Python קורא ומסיר חתימה זו בעת פענוח, ומוסיף אותה בעת קידוד.

עבור מקור UTF-8 מאומת עם BOM, השתמשו ב- --from-encoding utf-8-sig. בדרך כלל הכלי שומר UTF-8 ללא BOM; הוסיפו את --with-bom רק כאשר הדרישות של יישום היעד מחייבות זאת. שינוי של BOM אינו יכול להפוך את café ל- café. ניסוי זה אינו מבסס תאימות לנגן, עורך או פלטפורמת העלאה מסוימת כלשהי.

חמישה קבצים קטנים מראים מדוע תקינות UTF-8 לבדה אינה מספיקה

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

1
00:00:01,000 --> 00:00:04,000
Émile dit : « Le prix est de 12,50 €. »

2
00:00:05,000 --> 00:00:08,000
Le café est fermé.

ב-13 בספטמבר 2026, סקריפט מבוסס הספרייה הסטנדרטית של Python 3.14.3 יצר חמישה ייצוגי בייטים והשווה כל אחד מהם למקור הידוע ההוא. אלו בדיקות בייטים ומחרוזות דטרמיניסטיות, ולא מבחן ביצועים לאיכות התרגום. שמרו את הקבצים המקושרים בדיסק במקום להעתיק את התצוגה המקדימה שלהם בדפדפן: ההבדלים בין הבייטים הם כל מהות הניסוי.

עותק להורדהבייטיםUTF-8 קפדני?טקסט תקין בפענוח כ-UTF-8?נשמר U+FFFD בטקסט ה-UTF-8 שלו
UTF-8 מקורי132כןכן0
Windows-1252 מקורי125לאלא ניתן לפענוח כ-UTF-8; תקין תחת cp1252לא רלוונטי
מפענח שגוי, נשמר מחדש כ-UTF-8147כןלא0
תווי החלפה, נשמר מחדש כ-UTF-8137כןלא6
UTF-8 שהומר כהלכה132כןכן0

כל עותק שומר על שתי מחרוזות חותמת הזמן המקוריות. הקובץ שהומר כהלכה זהה בייט-אחר-בייט למקור ה-UTF-8. שני קובצי ה-UTF-8 הפגומים מוכיחים נקודה צרה יותר אך שימושית: לא קידוד תקין ולא חותמות זמן ללא שינוי מעידים על טקסט כתוביות תקין. התאמה של חותמות זמן גם אינה אומרת דבר לגבי השאלה האם רצועה מומצאת זו אכן מתאימה לסרטון אמיתי.

כדי לשחזר את חמשת הקבצים בעצמכם, הורידו את reproduce.py והריצו אותו עם שם תיקייה שאינה קיימת:

python3 reproduce.py encoding-experiment

הסקריפט מייצר את קובצי הבדיקה וקובץ results.json המכיל את הטקסט המלא, ההמרות שבוצעו, הגיבובים (hashes), גרסת סביבת ההרצה ובדיקות האימות (assertions). השוו אותו אל תוצאות הניסוי המתועדות; חותמת זמן ההפקה תהיה שונה. הסקריפטים וקובצי ההדרכה המקוריים כוללים רישיון MIT.

בדיקות הממיר המקומי בחנו גם סירוב לדריסת פלט קיים, סירוב לנתיב מקור לא תקין, כשל בקידוד שגוי, דחיית U+FFFD, שימור מעברי שורה מסוג CRLF והפקת BOM מפורשת. בדיקות אלו מאמתות את התנהגות הקבצים של כלי זה. הן אינן בודקות רינדור בנגנים, תזמון מול מדיה אמיתית או תרגום באמצעות BookTranslator.

אם התווים השבורים כבר נשמרו בקובץ

ג'יבריש (mojibake) שנשמר: חקירת ההיסטוריה המדויקת

עותק הג'יבריש שלנו עבר שרשרת ידועה: בייטים מקוריים של UTF-8 פוענחו כ-Windows-1252, ולאחר מכן אותם תווים שגויים נשמרו כ-UTF-8. התוצאה כוללת את café ואת רצף האירו השבור €.

מכיוון שהמרה מסוימת זו לא איבדה אף בייט, סקריפט השחזור מסוגל להפוך אותה: לקודד את הטקסט השגוי בחזרה דרך cp1252, ולאחר מכן לפענח את הבייטים שהתקבלו כ-UTF-8. הוא מאמת את הטקסט ששוחזר מול המקור.

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

תווי החלפה שנשמרו: האות החסרה אינה מקודדת שם

דוגמת האובדן נוצרה על ידי פענוח בייטים של Windows-1252 כ-UTF-8 כאשר החלפת תווים מופעלת, ולאחר מכן שמירת התוצאה. תווים מקוריים שונים הפכו לאותו סימן � . הסימן שנשמר אינו מכיל מספיק מידע כדי לזהות איזה תו מקורי הופיע באותו מיקום.

אל תבלבלו זאת עם מצב שבו אתם רק רואים � זאת ביישום כלשהו. אם הבייטים המקוריים נותרו ללא שינוי, פענוח נכון עדיין עשוי לשחזר את הטקסט — כפי שקורה עם מקור ה-Windows-1252 שלנו. בדקו היטב את המקור הזה לפני שתכריזו על אובדן נתונים.

אם העותק היחיד שנותר אכן החליף את הטקסט החסר ב-U+FFFD או בסימני שאלה מילוליים, ייצאו מחדש או השיגו מקור נקי, לחלופין אמתו תמלול ידני מול חומר מהימן. סימן שאלה רגיל עשוי להיות גם סימן פיסוק לגיטימי; עצם נוכחותו אינה מוכיחה דבר. ניחוש סביר של מודל הוא עדיין בגדר השערה, ולא שחזור אמיתי של נתוני הקובץ.

סיימו עם מקור קריא — לא רק עם פקודה שהסתיימה בהצלחה

לפני שתאשרו את הקובץ המתוקן, השוו מילים וסמלים מייצגים מול המקור המהימן, ודאו ששורות הכתוביות וחותמות הזמן לא השתנו, ופתחו את הקובץ החדש ביישום שבו תשתמשו בו בפועל. הסקריפט שומר על הטקסט המפוענח; הוא אינו כלי לאימות תחביר של SRT ואינו מבחן קבלה לניגון וידאו.

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

רק לאחר שטקסט המקור מהימן — ובמידה שאתם אכן זקוקים לשפה נוספת — המשיכו אל מתרגם הכתוביות של BookTranslator ואל תהליך העבודה לתרגום כתוביות ב-AI. התייחסו לתיקון הקידוד, לתרגום ולצפייה ברצועה הסופית כאל משימות נפרדות. הצלחה באחת מהן אינה מהווה הוכחה לכך שהאחרות הצליחו.

פוסטים קשורים