C#에서 Ude를 사용한 키릴 문자 인코딩 오류 해결 방법
C#의 Ude 라이브러리는 키릴 문자가 포함된 텍스트 파일의 인코딩을 때때로 잘못 판단하여, 올바른 Windows-1251 대신 'Macintosh'라고 보고합니다. 이로 인해 텍스트를 읽을 때 깨진 문자(모지바케)가 나타나며, 예상대로 읽히는 러시아어가 이상한 기호로 표시됩니다. 이 문제는 Notepad++에서도 발생하며, CharsetDetector를 사용하는 코드 내부에서도 나타납니다.
GetFileEncoding 메서드에서 Ude는 cdet.Charset를 'Macintosh'로 반환하여 이후 변환 과정에서 오류가 발생합니다:
public static Encoding GetFileEncoding(string filename)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
using (FileStream fs = File.OpenRead(filename))
{
Ude.CharsetDetector cdet = new Ude.CharsetDetector();
cdet.Feed(fs);
cdet.DataEnd();
if (cdet.Charset != null)
{
return Encoding.GetEncoding(cdet.Charset);
}
}
return Encoding.GetEncoding(CodePages.Windows1251);
}
ChangeEncodingForMidFile에서 이 잘못된 인코딩을 적용하면 상황이 악화되며, 텍스트가 제대로 읽히지 않고 새로운 파일에 저장될 때 손상됩니다.
private static void ChangeEncodingForMidFile(string midFile,
Encoding midFileEncoding,
string newFullMidFileName)
{
using StreamReader reader = new StreamReader(midFile, midFileEncoding);
using StreamWriter writer = new StreamWriter(
newFullMidFileName,
false,
Encoding.GetEncoding(CodePages.Windows1251)
);
writer.Write(reader.ReadToEnd());
File.Delete(midFile);
File.Move(newFullMidFileName, midFile);
}
MacCyrillic과 Windows-1251의 차이 분석
MacCyrillic(CodePages.Macintosh)와 Windows-1251은 키릴 문자에 대해 서로 다른 바이트 범위를 사용합니다. 일반적인 러시아어 텍스트(희귀 기호 없음)에서는 한 인코딩에 특유하지만 다른 인코딩에서는 흔한 '의심스러운' 바이트를 식별할 수 있습니다:
- Macintosh에 의심스러운 바이트: Windows-1251에서 흔한 바이트 (0xAB, 0xB8–0xB9, 0xBB, 0xC0–0xC7, 0xC9, 0xCB–0xCF, 0xD2–0xDB, 0xFF).
- Windows-1251에 의심스러운 바이트: Macintosh에서 흔한 바이트 (0x80–0x8F, 0x90–0x97, 0x99–0x9F).
이 두 집합은 휴리스틱 재검증에 사용됩니다.
private static readonly ArrayList<byte> StrangeForMacintoshBytes = new ArrayList<byte>
{
0xAB,
0xB8, 0xB9, 0xBB,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC9, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB,
0xFF
};
private static readonly ArrayList<byte> StrangeForWindows1251Bytes = new ArrayList<byte>
{
0x80, 0x81, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F
};
커스텀 인코딩 검출 구현: CustomGetEncoding
Macintosh 또는 MacCyrillic이 감지되면 CustomGetEncoding 메서드가 실행됩니다:
if (cdet.Charset != null)
{
var encoding = Encoding.GetEncoding(cdet.Charset);
if (encoding.CodePage == CodePages.Macintosh || encoding.CodePage == CodePages.MacCyrillic)
return CustomGetEncoding(encoding, filename);
}
CustomGetEncoding의 로직은 다음과 같습니다:
- 파일의 바이트를 스캔합니다.
StrangeForMacintoshBytes에 속하는 바이트가 발견되면 Windows-1251을 반환합니다.- 그렇지 않지만
StrangeForWindows1251Bytes에 속하는 바이트가 있으면 Macintosh를 반환합니다. - 의심스러운 바이트가 없으면 기본적으로 Windows-1251을 반환합니다.
이 방식은 단순한 러시아어 텍스트에는 효과적이지만, 모든 경우에 적용되지는 않습니다.
한계점과 권장 사항
이 접근법의 단점:
- 희귀 기호가 없는 키릴 텍스트에만 적용 가능.
- UTF-8이나 기타 인코딩은 처리 불가.
- 휴리스틱 기반으로 신뢰성 있는 감지 메커니즘은 아님.
사용자에게 권장되는 절차:
- 파일을 Notepad++에서 열기.
- Windows-1251, UTF-8 등 다양한 인코딩을 시도해 깨짐이 없을 때까지 확인.
- 텍스트를 복사하기.
- 목표 인코딩으로 새 파일을 만들고 내용 붙여넣기.
- 저장하기.
이 수동 작업조차도 Ude가 인코딩을 잘못 판단할 경우 완전히 성공하지 못할 수 있습니다.
다른 인코딩 감지 라이브러리들도 유사한 문제를 겪습니다. 자동 감지는 본질적으로 확률적이며, 텍스트의 바이트 빈도 패턴에 의존합니다.
핵심 요약
- Ude는 키릴 파일에서 MacCyrillic과 Windows-1251을 자주 혼동합니다.
- '의심스러운 바이트' 휴리스틱을 활용해 라이브러리 수정 없이 감지 오류를 해결할 수 있습니다.
- 이 해결책은 기본적인 러시아어 텍스트에만 유효합니다.
- 항상 처리 전에 Notepad++에서 인코딩을 수동으로 확인하세요.
- 인코딩 감지는 확률적입니다. 오류는 피할 수 없습니다.
— Editorial Team
아직 댓글이 없습니다.