Chyby detekce kódování Cyrilice v C# pomocí knihovny Ude
Knihovna Ude v jazyce C# někdy nesprávně určuje kódování textových souborů obsahujících písmo Cyrilice, místo Windows-1251 označuje Macintosh. To způsobuje zkreslení textu při čtení – místo správného ruského obsahu se objevují "krátkozáblesky". Tento problém se projevuje jak v aplikaci Notepad++, tak i v kódu používajícím CharsetDetector.
V metodě GetFileEncoding knihovny Ude vrátí cdet.Charset jako 'Macintosh', což způsobí chybu při následné konverzi:
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);
}
Použití této kódování ve funkci ChangeEncodingForMidFile tento problém zhoršuje: text se čte špatně a zapisuje do nového souboru s poškozeným obsahem.
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);
}
Rozdíly mezi MacCyrillic a Windows-1251
Kódování MacCyrillic (CodePages.Macintosh) a Windows-1251 mají odlišné rozsahy bajtů pro kyrilské znaky. Pro typický ruský text bez vzácných znaků lze identifikovat "podivné" bity, které nejsou charakteristické pro jednu z kódování:
- Podivné pro Macintosh: bity typické pro Windows-1251 (0xAB, 0xB8–0xB9, 0xBB, 0xC0–0xC7, 0xC9, 0xCB–0xCF, 0xD2–0xDB, 0xFF).
- Podivné pro Windows-1251: bity typické pro Macintosh (0x80–0x8F, 0x90–0x97, 0x99–0x9F).
Tyto množiny se používají k heuristickému ověření.
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
};
Implementace metody CustomGetEncoding
Metoda CustomGetEncoding se aktivuje při detekci Macintosh nebo MacCyrillic:
if (cdet.Charset != null)
{
var encoding = Encoding.GetEncoding(cdet.Charset);
if (encoding.CodePage == CodePages.Macintosh || encoding.CodePage == CodePages.MacCyrillic)
return CustomGetEncoding(encoding, filename);
}
Logika CustomGetEncoding:
- Prochází bajty souboru.
- Pokud najde bity z
StrangeForMacintoshBytes, vrátí Windows-1251. - Jinak, pokud najde bity z
StrangeForWindows1251Bytes, vrátí Macintosh. - Pokud žádné "podivné" bity nenajde, použije Windows-1251 jako výchozí.
Toto řešení funguje pro jednoduchý ruský text, ale není univerzální.
Omezení a doporučení
Nedostatky tohoto přístupu:
- Platí pouze pro Cyrilici bez vzácných znaků.
- Nepokrývá UTF-8 ani jiná kódování.
- Je založeno na heuristice, nikoli na spolehlivém detektoru.
Pro uživatele:
- Otevřete soubor v Notepad++.
- Zvolte kódování bez zkreslení (Windows-1251, UTF-8).
- Zkopírujte text.
- Vytvořte nový soubor s cílovou kódováním a vložte obsah.
- Uložte soubor.
I tento postup nezaručuje 100% úspěch, pokud knihovna Ude selže i přesto, že je výsledek vizuálně správný.
Jiné knihovny pro detekci kódování ukázaly podobné problémy. Automatická detekce je vždy pravděpodobnostní a závisí na statistice bajtů v textu.
Důležité informace
- Knihovna Ude často zaměňuje MacCyrillic a Windows-1251 u souborů s Cyrilicí.
- Heuristika na "podivných" bitech opravuje detekci bez nutnosti přepsání knihovny.
- Přístup funguje pouze pro jednoduchý ruský text.
- Doporučuje se ruční kontrola v Notepad++ před načtením.
- Pravděpodobnostní povaha detekce kódování znamená, že chyby jsou nevyhnutelné.
— Editorial Team
Zatím žádné komentáře.