Sửa lỗi mã hóa phụ đề SRT mà không làm mất văn bản gốc
Chẩn đoán phụ đề SRT bị lỗi font, phân biệt lỗi giải mã với ký tự bị mất, và tạo bản sao UTF-8 riêng biệt bằng công cụ Python an toàn cùng các mẫu thử có thể tái lập.

Nếu phụ đề SRT của bạn hiển thị café thay vì café, đừng vội lưu tệp ngay sang chuẩn UTF-8. Trước tiên, hãy giữ một bản sao nguyên vẹn các byte của tệp, xác định bảng mã giải mã giúp hiển thị đúng từ ngữ, rồi ghi văn bản đã kiểm tra sang một tệp riêng biệt. Việc lưu các ký tự sai dưới một bảng mã mới sẽ khiến các ký tự lỗi bị giữ nguyên vĩnh viễn.
Điểm phân biệt cốt lõi ở đây là mã hóa hợp lệ so với văn bản chính xác. Trong thử nghiệm gốc với hai đoạn phụ đề bên dưới, một tệp bị lỗi vẫn vượt qua bước kiểm tra UTF-8 nghiêm ngặt và không chứa bất kỳ ký tự thay thế nào. Thế nhưng văn bản tiếng Pháp của nó vẫn sai. Một tệp khác cũng vượt qua bước kiểm tra tương tự sau khi sáu ký tự gốc đã bị thay thế bằng �.
Hướng dẫn này cung cấp một công cụ Python cục bộ để kiểm tra và chuyển đổi, các tệp nguồn có thể tải về và một bài kiểm tra có thể tái lập. Hướng dẫn tập trung xử lý chẩn đoán ở cấp độ tệp và chuyển đổi tường minh—chứ không phải tự động nhận diện bảng mã, đồng bộ video, hay cam kết phục hồi các ký tự đã mất.
Trước tiên, hãy xác định lỗi thực sự nằm ở đâu
Phần mở rộng .srt chỉ xác định định dạng phụ đề chứ không đảm bảo bảng mã cụ thể nào. Tệp SRT chứa số thứ tự phụ đề, mốc thời gian, văn bản và các dấu phân cách; hồ sơ định dạng SRT của Thư viện Quốc hội Hoa Kỳ mô tả nó là văn bản thuần túy và không có một tiêu chuẩn mã hóa ký tự duy nhất.
Hãy dùng dấu hiệu nhìn thấy được làm lý do để kiểm tra, chứ đừng vội kết luận đó là nguyên nhân chuẩn xác:
| Hiện tượng bạn thấy | Điều cần kiểm tra | Bước xử lý tiếp theo phù hợp |
|---|---|---|
| Dấu hoặc biểu tượng hiển thị sai trong một ứng dụng | Việc mở lại tệp nguyên bản bằng bảng mã nguồn đã biết có hiển thị đúng văn bản không? | Nếu có, hãy dùng phương pháp giải mã tường minh đó trước khi xuất bản sao mới. |
café vẫn còn trong tệp được đọc chính xác ở chuẩn UTF-8 | Có phải trước đó UTF-8 đã bị đọc nhầm thành một bảng mã khác rồi lưu lại không? | Hãy quay lại các byte gốc, hoặc điều tra chính xác lịch sử chuyển đổi. Lưu lại dưới dạng UTF-8 thêm một lần nữa không phải là cách sửa lỗi. |
� xuất hiện tại vị trí vốn thuộc về một chữ cái hoặc ký hiệu | Ký tự U+FFFD có thực sự được lưu trong tệp không, hay ứng dụng hiện tại đang tự chèn nó vào khi hiển thị các byte không thể giải mã? | Kiểm tra tệp nguồn nguyên bản chưa qua chỉnh sửa. Một ký tự thay thế đã bị lưu lại sẽ không thể giúp xác định ký tự gốc ban đầu. |
| Các ô vuông xuất hiện trong trình phát, nhưng trình xem văn bản đáng tin cậy vẫn hiển thị đúng các ký tự dự kiến | Các điểm mã (code point) bên dưới có chính xác không? Trình phát có đang tải cùng một tệp đó không? | Hãy kiểm tra khả năng giải mã, độ bao phủ phông chữ hoặc cài đặt kết xuất của trình phát trước khi thay đổi tệp. |
Ký tự và hình dạng hiển thị của chúng là hai khái niệm khác nhau. Tài liệu giải thích về Unicode của Python phân biệt rõ giữa điểm mã và glyph do phông chữ kết xuất. Văn bản hiển thị chính xác trong trình biên tập cho thấy khả năng cao vấn đề nằm ở phía trình phát; điều đó không chứng minh rằng việc cài đặt một phông chữ cụ thể sẽ khắc phục được lỗi. Không có phông chữ hoặc trình phát nào được thử nghiệm cho bài viết này.
Sao lưu các byte, sau đó kiểm tra kết quả giải mã
Tải về subtitle_encoding.py và đặt nó cạnh tệp SRT bạn muốn kiểm tra. Các lệnh này yêu cầu máy đã cài sẵn Python 3 và không cần thêm gói bổ trợ nào. Các bước kiểm tra cục bộ ở đây sử dụng Python 3.14.3 trên macOS. Nếu bản cài đặt Windows của bạn sử dụng Python launcher, hãy thay py -3 bằng python3; môi trường đó chưa được thử nghiệm tại đây.
Mở terminal trong thư mục đó. Trong các ví dụ này, hãy thay input.srt bằng tên tệp thực tế của bạn. Giữ nguyên dấu ngoặc kép quanh các đường dẫn có chứa khoảng trắng.
Tạo một bản sao nguyên vẹn
python3 subtitle_encoding.py backup "input.srt" "original-bytes.srt"
Tệp đích không được tồn tại từ trước. Công cụ sẽ sao chép các byte mà không giải mã chúng, đọc lại bản sao và báo cáo mã băm SHA-256 tương ứng. Nó cũng sẽ từ chối nếu đường dẫn nguồn trùng với đường dẫn đích. Hãy giữ lại bản sao lưu này ngay cả khi bạn đã tạo được phụ đề sử dụng được.
Kiểm tra UTF-8 mà không lưu bất kỳ nội dung nào
python3 subtitle_encoding.py inspect "original-bytes.srt"
Báo cáo bao gồm strict_utf8, utf8_bom, bảng mã giải mã đã chọn, và—nếu giải mã thành công—bản xem trước văn bản cùng với replacement_characters . Chế độ xem văn bản mặc định của nó sử dụng utf-8-sig, giúp xử lý tốt phần chữ ký UTF-8 ở đầu tệp.
strict_utf8: falseđồng nghĩa với việc các byte không vượt qua được bước kiểm tra UTF-8. Điều này không cho bạn biết bảng mã nào khác mới là chính xác.strict_utf8: truenghĩa là chúng có thể giải mã được dưới dạng UTF-8. Điều này không đồng nghĩa với việc câu chữ hiển thị đúng.- Số lượng ký tự thay thế khác 0 đồng nghĩa với việc bảng mã được chọn đã tạo ra các ký tự U+FFFD. Hãy kiểm tra kỹ chúng trước khi tạo tệp mới.
Lệnh kiểm tra sẽ in ra chuỗi JSON an toàn với mã ASCII để phông chữ của cửa sổ dòng lệnh không làm sai lệch bản chất ký tự: \u00e9 có nghĩa là é, và \ufffd biểu thị ký tự thay thế. Để kiểm tra chi tiết một dòng nghi vấn, hãy yêu cầu theo số thứ tự dòng thực tế—chứ không phải số thứ tự đoạn phụ đề (cue):
python3 subtitle_encoding.py inspect "original-bytes.srt" --encoding cp1252 --line 3
Đây là bước kiểm tra ở chế độ chỉ đọc cho Windows-1252, codec cp1252 của Python. Chỉ sử dụng bảng mã này khi các thiết lập xuất tệp hoặc lịch sử nguồn gốc hỗ trợ lựa chọn đó, chứ không phải vì ví dụ này tình cờ dùng tiếng Pháp. Báo cáo chi tiết từng dòng sẽ nêu tên từng ký tự và hiển thị điểm mã (code point) của nó; U+20AC chính là ký hiệu đồng euro.
Chọn bảng mã dựa trên cơ sở xác thực, không dựa vào kết quả xem trước thành công đầu tiên
Hãy hỏi người tạo tệp về bảng mã xuất thực tế, kiểm tra phần cài đặt của ứng dụng xuất tệp hoặc đối chiếu với bản ghi gốc đáng tin cậy. Rà soát lại các tên riêng có dấu, dấu câu, ký hiệu tiền tệ và các dòng tiêu biểu rải rác trong toàn bộ tệp. Nếu bạn không biết ngôn ngữ đó, một bộ giải mã đọc được chữ cũng không thể thay bạn làm công việc đối chiếu này.
Thuật ngữ “ANSI” không đủ cụ thể để chọn codec nguồn. Windows-1252 và Latin-1 cũng không thể thay thế cho nhau. Trong thử nghiệm đã đưa ra, byte đơn 80 giải mã thành € dưới bảng mã cp1252, nhưng lại trở thành ký tự điều khiển U+0080 theo chuẩn latin-1. Cả hai thao tác đều thành công. Chỉ có nguồn gốc đã biết mới cho chúng ta biết đâu là nội dung thực sự dự định hiển thị.
Các ngôn ngữ khác có thể dùng những bảng mã cũ khác nhau, nhưng chỉ riêng tên ngôn ngữ thì không thể xác định được một bảng mã cụ thể. Nếu không rõ nguồn gốc và các cách đọc khả dĩ không khớp nhau, hãy dừng lại trước khi chuyển đổi để tìm kiếm bằng chứng xác thực hơn về nguồn dữ liệu.
Chỉ chuyển đổi sau khi văn bản nguồn đã đọc được bình thường
Đối với tệp nguồn đã xác nhận là Windows-1252, hãy tạo một tệp UTF-8 riêng biệt:
python3 subtitle_encoding.py convert "original-bytes.srt" "repaired-utf8.srt" --from-encoding cp1252
python3 subtitle_encoding.py inspect "repaired-utf8.srt"
Công cụ chuyển đổi sẽ giải mã toàn bộ tệp nguồn theo chế độ nghiêm ngặt (strict), mã hóa văn bản đó sang UTF-8, kiểm tra xem việc giải mã đầu ra có trả về đúng văn bản đó hay không, rồi đọc lại các byte đã ghi. Công cụ không chỉnh sửa số thứ tự phụ đề, mốc thời gian, lời thoại, thẻ định dạng hay ký tự xuống dòng. Chuỗi byte mới có thể khác đi dù văn bản sau khi giải mã vẫn hoàn toàn giống nhau.
Công cụ sẽ chủ động từ chối:
- ghi đè lên tệp đích đã tồn tại;
- tiếp tục xử lý khi gặp lỗi giải mã nghiêm ngặt; hoặc
- ghi văn bản có chứa U+FFFD, ngay cả khi ký tự đó vốn là có chủ đích.
Hạn chế cuối cùng này được thiết lập một cách cẩn trọng: công cụ này không thể tự ý quyết định xem ký tự thay thế đó vốn đại diện cho chữ gì. Việc loại bỏ nó để lệnh chạy qua được sẽ làm mất đi dấu vết lỗi thay vì khôi phục lại văn bản. Tài liệu về trình xử lý lỗi của Python giải thích lý do tại sao replace và ignore lại khác với giải mã nghiêm ngặt: chúng sẽ thay thế hoặc loại bỏ dữ liệu gặp sự cố. Cả hai cách này đều không nên dùng trong bước chuyển đổi này.
Nếu xảy ra lỗi I/O, tuyệt đối không sử dụng tệp đầu ra bị lỗi đó. Một tệp mới dang dở có thể vẫn còn sót lại; hãy giữ nguyên tệp gốc và đặt một tên tệp đích mới cho lần thử sau. Toàn bộ hành vi và cách sử dụng công cụ đều có trong tệp README có thể tải về.
Còn UTF-8 có BOM thì sao?
UTF-8 BOM là chuỗi byte mở đầu EF BB BF. utf-8-sig Codec của Python sẽ loại bỏ dấu hiệu nhận biết đó khi giải mã và thêm nó vào khi mã hóa.
Đối với nguồn đã xác nhận là UTF-8 có BOM, hãy dùng --from-encoding utf-8-sig. Công cụ này thường ghi UTF-8 không có BOM; chỉ thêm --with-bom khi các yêu cầu của ứng dụng tiếp nhận đòi hỏi điều đó. Việc thay đổi BOM không thể biến café thành café. Thử nghiệm này không nhằm xác định khả năng tương thích với bất kỳ trình phát, trình chỉnh sửa hoặc nền tảng tải lên cụ thể nào.
Năm tệp nhỏ cho thấy vì sao tính hợp lệ của UTF-8 là chưa đủ
Thử nghiệm sử dụng hai đoạn phụ đề tiếng Pháp hoàn toàn tự viết. Chúng không được lấy từ phim, khách hàng hay bất kỳ sản phẩm dịch thuật nào:
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é.
Vào ngày 13 tháng 9 năm 2026, một đoạn mã thư viện chuẩn Python 3.14.3 đã tạo ra năm biểu diễn byte và so sánh từng biểu diễn với nguồn gốc đã biết đó. Đây là các kiểm tra byte và chuỗi tất định, không phải điểm chuẩn đánh giá chất lượng dịch thuật. Hãy lưu các tệp được liên kết vào ổ đĩa thay vì sao chép phần xem trước trên trình duyệt: các byte khác nhau chính là trọng tâm của thử nghiệm này.
| Bản sao có thể tải xuống | Byte | UTF-8 chuẩn? | Văn bản chính xác khi giải mã dưới dạng UTF-8? | Đã lưu U+FFFD trong văn bản UTF-8 |
|---|---|---|---|---|
| UTF-8 gốc | 132 | Có | Có | 0 |
| Windows-1252 gốc | 125 | Không | Không thể giải mã dưới dạng UTF-8; hiển thị đúng với cp1252 | Không áp dụng |
| Sai bộ giải mã, lưu lại dưới dạng UTF-8 | 147 | Có | Không | 0 |
| Ký tự thay thế, lưu lại dưới dạng UTF-8 | 137 | Có | Không | 6 |
| UTF-8 đã chuyển đổi chính xác | 132 | Có | Có | 0 |
Mỗi bản sao đều giữ nguyên hai chuỗi mốc thời gian đó. Tệp được chuyển đổi chính xác trùng khớp từng byte so với bản gốc UTF-8. Hai tệp UTF-8 bị hỏng chứng minh một điều hẹp hơn nhưng hữu ích: cả việc mã hóa hợp lệ lẫn mốc thời gian không đổi đều không khẳng định được văn bản phụ đề là chính xác. Việc các mốc thời gian trùng khớp cũng không nói lên được liệu bản phụ đề tự tạo này có khớp với một video thực tế hay không.
Để tự mình tái tạo lại năm tệp này, hãy tải về reproduce.py và chạy tập lệnh với tên một thư mục chưa tồn tại:
python3 reproduce.py encoding-experiment
Tập lệnh sẽ ghi các tệp mẫu và một results.json chứa toàn bộ văn bản, các phép biến đổi, mã băm, phiên bản môi trường chạy và các câu lệnh khẳng định (assertions). Hãy so sánh nó với kết quả thử nghiệm đã ghi nhận; mốc thời gian tạo sẽ khác nhau. Các tập lệnh và tệp hướng dẫn gốc đi kèm với một giấy phép MIT.
Các bước kiểm tra trình chuyển đổi cục bộ cũng đã thử nghiệm trường hợp từ chối ghi đè đầu ra hiện có, từ chối đường dẫn nguồn, lỗi do sai codec, từ chối U+FFFD, giữ nguyên CRLF và xuất BOM rõ ràng. Các kiểm tra đó xác minh hành vi tệp của công cụ này. Chúng không kiểm tra khả năng kết xuất của trình phát, khớp thời gian trên phương tiện thực tế hay bản dịch của BookTranslator.
Nếu các ký tự lỗi đã bị lưu đè
Lỗi font (mojibake) đã bị lưu: điều tra chính xác lịch sử thay đổi
Bản sao bị lỗi font của chúng tôi đã trải qua một chuỗi xử lý đã biết: các byte UTF-8 gốc bị giải mã nhầm thành Windows-1252, sau đó các ký tự sai đó lại được lưu dưới dạng UTF-8. Kết quả bao gồm café và chuỗi ký tự euro bị hỏng €.
Vì phép biến đổi cụ thể này không làm mất byte nào, tập lệnh tái tạo có thể đảo ngược nó: mã hóa lại văn bản sai thông qua cp1252, sau đó giải mã các byte thu được dưới dạng UTF-8. Tập lệnh sẽ xác minh văn bản được khôi phục so với bản gốc.
Đó là bằng chứng cho chuỗi xử lý đã biết này, chứ không phải là chỉ dẫn để áp dụng thao tác “sửa lỗi font mojibake” hàng loạt cho mọi tệp SRT. Một tệp có thể chứa các ký tự hợp lệ, nhiều lịch sử can thiệp lẫn lộn hoặc văn bản đã bị thay đổi bởi lần sửa lỗi trước đó. Hãy ưu tiên tệp nguồn nguyên bản chưa chỉnh sửa và quy trình chuyển đổi thông thường. Nếu chỉ còn lại bản lỗi font đã bị lưu, hãy sao lưu giữ nguyên tệp đó và xác định rõ cách nó được tạo ra trước khi thử thực hiện phép biến đổi nghịch đảo trên một bản sao khác.
Ký tự thay thế đã bị lưu lại: ký tự gốc bị thiếu không còn được mã hóa ở đó
Tệp mẫu bị mất dữ liệu được tạo ra bằng cách giải mã các byte Windows-1252 dưới dạng UTF-8 với chế độ thay thế được bật, sau đó lưu lại kết quả. Các ký tự gốc khác nhau đều đã biến thành cùng một ký tự đánh dấu � . Ký tự đánh dấu đã lưu này không còn chứa đủ thông tin để xác định ký tự gốc nào từng nằm ở vị trí đó.
Đừng nhầm lẫn điều này với việc chỉ đơn thuần nhìn thấy � trong một ứng dụng. Nếu các byte gốc vẫn chưa bị ghi đè, việc giải mã chính xác vẫn có thể khôi phục lại văn bản—giống như cách chúng tôi đã làm với tệp nguồn Windows-1252. Hãy kiểm tra tệp nguồn đó trước khi kết luận là dữ liệu đã mất hoàn toàn.
Nếu bản sao duy nhất còn lại thực sự đã bị thay thế văn bản bị thiếu bằng U+FFFD hoặc dấu chấm hỏi thông thường, hãy xuất lại hoặc tìm lại tệp nguồn nguyên vẹn, hoặc đối chiếu bản chép lời thủ công với tài liệu đáng tin cậy. Dấu chấm hỏi thông thường cũng có thể là dấu câu hợp lệ; riêng sự xuất hiện của nó không chứng minh được điều gì. Phương án thay thế hợp lý của một mô hình AI chỉ là phỏng đoán, chứ không phải dữ liệu tệp được khôi phục.
Kết thúc bằng một tệp nguồn đọc được—chứ không chỉ là một lệnh chạy thành công
Trước khi chấp nhận tệp đã sửa, hãy so sánh các từ và ký hiệu tiêu biểu với nguồn đáng tin cậy, xác nhận các dòng số thứ tự phụ đề (cue) và mốc thời gian không bị thay đổi, rồi mở tệp mới trong ứng dụng bạn sẽ dùng. Tập lệnh này chỉ bảo toàn văn bản đã giải mã; nó không phải là công cụ kiểm tra cú pháp SRT hay quy trình kiểm thử phát video.
Nếu giờ đây bạn đã đọc được phụ đề và không cần thêm ngôn ngữ nào khác, công việc đã hoàn tất. Nếu bạn cần xem trực tiếp cùng video hoặc chỉnh sửa thêm, bài so sánh phần mềm phụ đề sẽ giải thích vai trò của từng công cụ.
Chỉ khi văn bản nguồn đã chuẩn xác—và bạn thực sự cần ngôn ngữ khác—hãy chuyển sang Trình dịch phụ đề của BookTranslator và quy trình dịch phụ đề bằng AI. Hãy coi việc sửa lỗi mã hóa, dịch thuật và kiểm tra phụ đề hiển thị lần cuối là những bước riêng biệt. Kết quả của bước này không phải là bảo chứng cho sự thành công của các bước khác.
Bài viết liên quan





