원본 텍스트 손실 없이 SRT 자막 인코딩 오류 해결하기
깨진 SRT 텍스트를 진단하고, 디코딩 오류와 유실된 문자를 구분하며, 안전한 Python 도구와 재현 가능한 샘플을 사용해 별도의 UTF-8 사본을 생성해 보세요.

SRT 자막에 café 대신 café와 같이 표시된다고 해서 파일을 즉시 UTF-8로 다시 저장하지 마세요. 먼저 원본 바이트를 그대로 보존한 사본을 남겨두고, 올바른 단어로 표시되는 디코딩 방식을 찾은 다음, 검증된 텍스트를 별도의 파일로 저장해야 합니다. 잘못된 문자가 표시된 상태에서 새로운 인코딩으로 저장하면 잘못된 문자 자체가 영구적으로 굳어집니다.
여기서 핵심은 유효한 인코딩과 올바른 텍스트의 차이를 구분하는 것입니다. 아래의 두 개 큐(cue) 테스트를 보면, 손상된 파일 중 하나는 엄격한 UTF-8 유효성 검사를 통과하고 대체 문자도 전혀 포함하지 않습니다. 하지만 프랑스어 텍스트는 여전히 잘못되어 있습니다. 또 다른 파일은 원본 문자 6개가 �.
이 가이드에서는 로컬 Python 검사 및 변환 도구, 다운로드 가능한 원본 파일, 재현 가능한 테스트를 제공합니다. 이 글은 자동 인코딩 감지, 비디오 싱크 조정, 또는 이미 손실된 문자 복구를 보장하는 것이 아니라, 파일 단위의 진단과 명시적 변환을 다룹니다.
실제로 무엇이 문제인지 먼저 파악하기
확장자가 .srt 라고 해서 특정 인코딩이 보장되는 것은 아니며, 단지 자막 형식임을 나타낼 뿐입니다. SRT는 큐 번호, 타임스탬프, 텍스트, 구분 기호를 담고 있습니다. 미국 의회도서관의 SRT 포맷 기술 문서 에서도 단일 문자 인코딩 표준이 없는 일반 텍스트로 설명합니다.
눈에 보이는 증상은 그 자체로 최종 진단이 아니라, 원인을 조사해야 하는 신호로 보아야 합니다.
| 화면에 보이는 증상 | 확인해야 할 사항 | 적절한 다음 단계 |
|---|---|---|
| 특정 앱에서 악센트나 기호가 깨져 보임 | 손대지 않은 원본 파일을 원래의 소스 인코딩으로 다시 열었을 때 올바른 텍스트가 표시되는가? | 그렇다면 새 사본으로 내보내기 전에 해당 디코딩을 명시적으로 적용하세요. |
café UTF-8로 정상적으로 읽어들인 파일에 여전히 | 이전에 UTF-8을 다른 인코딩으로 잘못 읽은 상태에서 저장했나요? | 원본 바이트로 되돌아가거나 정확한 변환 내역을 확인하세요. UTF-8로 한 번 더 저장한다고 해서 복구되지 않습니다. |
� 문자가 문자나 기호가 있어야 할 자리에 표시됨 | U+FFFD가 파일에 실제로 저장되어 있나요, 아니면 현재 앱이 디코딩할 수 없는 바이트를 표시하면서 임의로 삽입하는 중인가요? | 수정되지 않은 원본을 검사하세요. 파일에 이미 대체 문자로 저장되어 있다면 원래 문자가 무엇이었는지 파악할 수 없습니다. |
| 플레이어에는 네모 모양으로 깨져 나오지만, 신뢰할 수 있는 텍스트 뷰어에는 의도한 문자가 정상적으로 표시됨 | 기본 코드 포인트가 올바른가요? 플레이어가 동일한 파일을 불러오고 있나요? | 파일을 수정하기 전에 플레이어의 디코딩 설정, 폰트 지원 범위, 렌더링 설정을 먼저 확인하세요. |
문자와 화면에 표시되는 형태는 서로 다릅니다. Python의 유니코드 설명 문서 에서는 코드 포인트와 폰트로 렌더링된 글리프를 명확히 구분합니다. 에디터에서 텍스트가 올바르게 보인다면 플레이어 쪽 문제일 가능성이 높지만, 특정 폰트를 설치한다고 해서 반드시 해결된다는 의미는 아닙니다. 본 글에서는 특정 폰트나 플레이어에 대한 별도 테스트를 진행하지 않았습니다.
바이트 백업 후 디코딩 상태 확인하기
먼저 subtitle_encoding.py 파일을 다운로드하여 확인하려는 SRT 파일과 같은 위치에 두세요. 이 명령어들을 실행하려면 Python 3가 설치되어 있어야 하며 추가 패키지는 필요하지 않습니다. 본문의 로컬 테스트 환경은 macOS의 Python 3.14.3 기준입니다. Windows 환경에서 Python 런처를 사용하는 경우 py -3 대신 python3를 사용하세요. 해당 환경은 본문에서 직접 테스트하지 않았습니다.
해당 폴더에서 터미널을 엽니다. 아래 예시에서는 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로 디코딩할 수 있음을 의미합니다. 그러나 실제 단어가 올바르다는 것을 보장하지는 않습니다 .- 대체 문자 개수가 0이 아니라면 선택한 디코딩 과정에서 U+FFFD 문자가 생성되었음을 뜻합니다. 새 파일을 만들기 전에 반드시 이를 확인하세요.
검사 결과는 터미널 글꼴 때문에 실제 문자가 왜곡되어 보이지 않도록 ASCII 안전 JSON으로 출력됩니다. \u00e9 는 é를 의미하며, \ufffd 는 대체 문자를 의미합니다. 의심스러운 줄을 자세히 살펴보려면 자막 큐 번호가 아닌 실제 물리적 줄 번호를 지정하세요.
python3 subtitle_encoding.py inspect "original-bytes.srt" --encoding cp1252 --line 3
이것은 Windows-1252(Python의 cp1252 코덱)에 대한 읽기 전용 테스트입니다. 이 예제에 우연히 프랑스어가 사용되었다고 해서 무작정 선택하지 말고, 내보내기 설정이나 원본 파일의 이력이 해당 선택을 뒷받침할 때만 사용하세요. 줄 단위 보고서에는 각 문자의 이름과 코드 포인트가 표시되며, 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"
이 변환 도구는 원본 파일 전체를 엄격 모드로 디코딩한 뒤, 해당 텍스트를 UTF-8로 인코딩하고, 생성된 출력물을 다시 디코딩했을 때 동일한 텍스트가 나오는지 검증하며, 기록된 바이트를 다시 읽어 들입니다. 자막 번호, 타임스탬프, 대사, 태그, 줄바꿈 등은 전혀 수정하지 않습니다. 디코딩된 텍스트가 완벽히 동일하더라도 새로운 바이트 시퀀스는 달라질 수 있습니다.
이 도구는 다음과 같은 상황에서 의도적으로 작업을 거부합니다.
- 기존 대상 파일 덮어쓰기
- 엄격 디코딩 오류 무시하고 진행하기
- U+FFFD가 포함된 텍스트 쓰기(해당 문자가 의도된 것이라 하더라도)
마지막 제한은 보수적인 안전장치입니다. 대체 문자가 원래 무엇을 나타내려 했는지는 이 도구가 판단할 수 없기 때문입니다. 명령어를 통과시키기 위해 이를 제거하는 것은 텍스트를 복원하는 것이 아니라 증거를 없애는 행위입니다. Python의 오류 처리기 문서 를 보면 replace 와 ignore 가 엄격 디코딩과 왜 다른지 설명되어 있습니다. 이들은 문제가 있는 데이터를 대체하거나 버립니다. 둘 다 이번 변환 단계에는 적합하지 않습니다.
I/O 오류가 발생하면 실패한 출력 파일을 사용하지 마세요. 불완전한 새 파일이 남아 있을 수 있으므로 원본을 보존하고 다음 시도에서는 새로운 대상 파일명을 사용하세요. 도구의 전체 동작 방식과 사용법은 다운로드 가능한 README.
BOM이 포함된 UTF-8은 어떻게 되나요?
UTF-8 BOM은 파일 시작 부분에 붙는 바이트 시퀀스인 EF BB BF입니다. Python의 utf-8-sig 코덱 은 디코딩할 때 이 시그니처를 제거하고, 인코딩할 때 이를 추가합니다.
BOM이 있는 것으로 확인된 UTF-8 소스의 경우 다음을 사용하세요: --from-encoding utf-8-sig. 이 도구는 기본적으로 BOM 없이 UTF-8로 저장합니다. 수신 애플리케이션에서 명시적으로 요구하는 경우에만 --with-bom 를 추가하세요. BOM을 변경한다고 해서 café 가 café(으)로 바뀌지는 않습니다. 본 실험은 특정 플레이어, 편집기 또는 업로드 플랫폼과의 호환성을 보증하지 않습니다.
단순한 UTF-8 유효성 검증만으로는 충분하지 않은 이유를 보여주는 5가지 파일
이 실험에서는 자체 제작한 두 개의 프랑스어 자막 큐를 사용합니다. 영화, 고객 데이터, 번역 제품 등에서 가져온 것이 아닙니다.
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é.
2026년 9월 13일, Python 3.14.3 표준 라이브러리 스크립트를 통해 5개의 바이트 표현을 생성하고 각각을 원본 소스와 비교했습니다. 이는 번역 품질 벤치마크가 아니라 결정론적인 바이트 및 문자열 검사입니다. 브라우저 미리보기에서 텍스트를 복사하지 말고 링크된 파일을 디스크에 직접 저장하세요. 서로 다른 바이트 표현 자체가 이 실험의 핵심입니다.
| 다운로드 가능한 복사본 | 바이트 크기 | 엄격한 UTF-8 여부 | UTF-8 디코딩 시 올바른 텍스트 여부 | UTF-8 텍스트 내 U+FFFD 저장 여부 |
|---|---|---|---|---|
| 원본 UTF-8 | 132 | 예 | 예 | 0 |
| 원본 Windows-1252 | 125 | 아니요 | UTF-8로 디코딩 불가, 다음 조건에서 정상: cp1252 | 해당 없음 |
| 잘못된 디코더 사용 후 UTF-8로 재저장 | 147 | 예 | 아니요 | 0 |
| 대체 문자 발생 후 UTF-8로 재저장 | 137 | 예 | 아니요 | 6 |
| 올바르게 변환된 UTF-8 | 132 | 예 | 예 | 0 |
모든 사본은 동일한 두 개의 타임스탬프 문자열을 유지합니다. 올바르게 변환된 파일은 UTF-8 원본과 바이트 단위까지 완벽히 일치합니다. 손상된 두 UTF-8 파일은 조금 더 좁지만 유용한 사실을 증명합니다. 즉, 인코딩이 유효하거나 타임스탬프가 변경되지 않았다고 해서 자막 텍스트가 올바르다고 단정할 수는 없다는 점입니다. 또한 타임스탬프가 일치한다고 해서 이 가상의 트랙이 실제 동영상에 잘 맞는지 여부까지 알려주는 것은 아닙니다.
이 다섯 개 파일을 직접 재현해 보려면 reproduce.py 파일을 다운로드한 후, 아직 존재하지 않는 디렉터리 이름을 지정하여 실행하세요.
python3 reproduce.py encoding-experiment
스크립트는 테스트용 픽스처 파일들과 함께 전체 텍스트, 변환 과정, 해시, 런타임 버전 및 어설션(검증) 결과가 담긴 results.json 파일을 생성합니다. 생성된 파일을 기록된 실험 결과와 비교해 보세요. 생성 타임스탬프만 다를 것입니다. 스크립트와 원본 교육용 파일에는 MIT 라이선스.
로컬 변환기 검증 과정에서는 이미 존재하는 출력 파일 덮어쓰기 거부, 소스 경로 오류 거부, 잘못된 코덱 실패 처리, U+FFFD 포함 거부, CRLF 유지, 명시적 BOM 출력 등도 함께 테스트했습니다. 이러한 검사는 이 도구의 파일 처리 동작을 검증하기 위한 것이며, 플레이어 렌더링, 실제 미디어와의 타이밍 일치 여부, 또는 BookTranslator 번역 기능 자체를 테스트하지는 않습니다.
깨진 글자가 이미 파일로 저장된 경우
저장된 모지바케: 정확한 변환 이력 파악하기
테스트에 사용된 모지바케 사본은 잘 알려진 특정 과정을 거쳤습니다. 원래의 UTF-8 바이트가 Windows-1252로 디코딩된 후, 그렇게 잘못 해석된 문자들이 다시 UTF-8로 저장된 것입니다. 그 결과 café 및 깨진 유로 기호 시퀀스인 €.
이 특정 변환 과정에서는 바이트 손실이 전혀 발생하지 않았기 때문에, 재현 스크립트를 통해 역변환이 가능합니다. 잘못된 텍스트를 다시 cp1252로 인코딩한 다음, 생성된 바이트를 UTF-8로 디코딩하면 됩니다. 스크립트는 이렇게 복구된 텍스트를 원본과 대조하여 검증합니다.
이는 이처럼 알려진 특정 변환 과정에 대한 증명일 뿐, 모든 SRT 파일에 일괄적으로 '모지바케 복구' 작업을 적용하라는 의미는 아닙니다. 파일에는 본래 정상적인 문자, 여러 인코딩이 혼합된 이력, 또는 이전 복구 시도로 인해 이미 변경된 텍스트가 포함되어 있을 수 있습니다. 가능하면 손상되지 않은 원본을 확보해 일반적인 변환 절차를 따르는 것이 가장 좋습니다. 이미 깨진 상태로 저장된 파일만 남아 있다면, 원본을 그대로 보존한 상태에서 별도의 사본을 만들어 어떤 과정을 거쳐 손상되었는지 먼저 확인한 후 역변환을 시도하세요.
저장된 대체 문자: 누락된 글자가 파일에 인코딩되어 있지 않은 경우
데이터 손실 샘플은 Windows-1252 바이트를 대체 문자가 활성화된 UTF-8로 디코딩한 후 그 결과를 저장하여 생성되었습니다. 서로 다른 원본 문자들도 모두 동일한 � 기호로 바뀌었습니다. 이미 저장된 대체 문자에는 원래 그 자리에 어떤 문자가 있었는지 식별할 수 있는 정보가 남아 있지 않습니다.
이를 앱 화면에서 단순하게 표시되는 것 � 과 혼동하지 마세요. 원본 바이트가 그대로 남아 있다면, Windows-1252 원본처럼 올바른 디코딩을 통해 텍스트를 정상적으로 복구할 수 있습니다. 완전히 손실되었다고 판단하기 전에 원본 데이터를 먼저 확인하세요.
남아 있는 유일한 사본에서 누락된 텍스트가 실제로 U+FFFD나 물음표 기호로 대체되어 저장되었다면, 깨끗한 원본을 다시 내보내거나 구해야 하며, 혹은 신뢰할 수 있는 자료를 바탕으로 수동 전사를 대조 확인해야 합니다. 일반적인 물음표는 정상적인 문장 부호일 수도 있으므로, 물음표가 있다는 사실 자체만으로는 아무것도 증명되지 않습니다. AI 모델이 그럴듯하게 채워 넣은 대체 텍스트 역시 추측일 뿐, 복구된 파일 데이터가 아닙니다.
명령어 성공에 그치지 않고, 실제로 읽을 수 있는 원본으로 마무리하기
복구된 파일을 최종적으로 사용하기 전에, 대표적인 단어와 기호를 신뢰할 수 있는 원본과 비교해 보고, 자막 번호 및 타임스탬프 라인이 변경되지 않았는지 확인한 다음, 실제로 사용할 애플리케이션에서 새 파일 을 직접 열어보세요. 이 스크립트는 디코딩된 텍스트를 보존할 뿐, SRT 문법 검사기나 재생 테스트 도구가 아닙니다.
이제 자막을 정상적으로 읽을 수 있고 다른 언어로의 번역이 필요 없다면 작업은 끝난 것입니다. 비디오를 직접 보면서 검토하거나 추가 편집이 필요하다면 자막 소프트웨어 비교 안내에서 각 도구의 역할을 확인해 보세요.
원본 텍스트를 신뢰할 수 있고 다른 언어로의 번역이 꼭 필요한 경우에만 BookTranslator 자막 번역기 와 AI 자막 번역 워크플로단계로 넘어가세요. 인코딩 복구, 번역, 최종 트랙 확인은 서로 독립된 별개의 작업으로 다루어야 합니다. 어느 한 단계가 성공했다고 해서 다른 단계의 성공까지 보장되는 것은 아닙니다.





