Zpět na domů

Ude chyby cyrilice C# detekce kódování

Článek rozebírá problém nesprávné detekce cyrilských kódování knihovnou Ude v C#. Navrhuje se heuristická metoda na základě 'podivných' bajtů pro korekci Macintosh/Windows-1251. Jsou popsány kód, omezení a doporučení pro manuální kontrolu.

Oprava chyb Ude: cyrilice v C# bez zdeformovaných znaků
Advertisement 728x90

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.

Google AdInline article slot
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:

Google AdInline article slot
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:

Google AdInline article slot
  • 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

Advertisement 728x90

Číst dál