Powrót do strony głównej

Ude błędy cyrylica C# detekcja kodowań

Artykuł analizuje problem błędnej detekcji cyrylickich kodowań biblioteką Ude w C#. Proponowana jest heurystyczna metoda na podstawie 'dziwnych' bajtów do korekty Macintosh/Windows-1251. Opisano kod, ograniczenia i rekomendacje dotyczące ręcznej weryfikacji.

Poprawka błędów Ude: cyrylica w C# bez krzaków
Advertisement 728x90

Błędy Ude przy wykrywaniu kodowania cyrylicznego w C#

Biblioteka Ude w C# czasem niepoprawnie wykrywa kodowanie plików tekstowych z alfabetem cyrylicznym, zwracając wartość 'Macintosh' zamiast Windows-1251. Wynika to z zakłóceń w tekście — zamiast poprawnego rosyjskiego zawartości pojawiają się tzw. 'krakozjaby'. Problem występuje zarówno w Notepad++ jak i w kodzie korzystającym z CharsetDetector.

W metodzie GetFileEncoding biblioteka Ude zwraca cdet.Charset jako 'Macintosh', co prowadzi do błędu podczas konwersji:

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);
}

Zastosowanie takiej kodowania w metodzie ChangeEncodingForMidFile pogarsza sytuację: tekst jest czytany niepoprawnie i zapisywany do nowego pliku z zakłóceniami.

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);
}

Analiza różnic między MacCyrillic a Windows-1251

Kodowania MacCyrillic (CodePages.Macintosh) i Windows-1251 mają różne zakresy bajtów dla znaków cyrylicznych. Dla typowego tekstu rosyjskiego bez rzadkich znaków można wyróżnić 'dziwne' bajty, które są nietypowe dla jednej z kodowań:

  • Dziwne dla Macintosh: bajty charakterystyczne dla Windows-1251 (0xAB, 0xB8–0xB9, 0xBB, 0xC0–0xC7, 0xC9, 0xCB–0xCF, 0xD2–0xDB, 0xFF).
  • Dziwne dla Windows-1251: bajty charakterystyczne dla Macintosh (0x80–0x8F, 0x90–0x97, 0x99–0x9F).

Te zestawy wykorzystuje się do heurystycznej weryfikacji.

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
};

Implementacja CustomGetEncoding

Metoda CustomGetEncoding aktywuje się przy wykryciu Macintosh lub 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:

  • Przeskanuj bajty pliku.
  • Jeśli napotkasz bajt z StrangeForMacintoshBytes — zwróć Windows-1251.
  • W przeciwnym razie, jeśli napotkasz bajt z StrangeForWindows1251Bytes — zwróć Macintosh.
  • Jeśli nie ma 'dziwnych' bajtów — wybierz Windows-1251 domyślnie.

To rozwiązuje problem dla prostego tekstu rosyjskiego, ale nie jest uniwersalne.

Ograniczenia i zalecenia

Wady podejścia:

Google AdInline article slot
  • Specyficzne dla alfabetu cyrylicznego bez rzadkich znaków.
  • Nie obejmuje UTF-8 ani innych kodowań.
  • Opiera się na heurystyce, a nie wiarygodnym detektorze.

Dla użytkowników:

  • Otwórz plik w Notepad++.
  • Wybierz kodowanie bez zakłóceń (Windows-1251, UTF-8).
  • Skopiuj tekst.
  • Stwórz nowy plik z docelową kodowaniem i wklej zawartość.
  • Zapisz plik.

Nawet to nie gwarantuje 100% sukcesu, jeśli Ude popełnia błąd mimo wizualnej weryfikacji.

Inne biblioteki do wykrywania kodowania pokazały podobne problemy. Automatyczne wykrywanie zawsze jest prawdopodobieństwowe i zależy od statystyki bajtów w tekście.

Co ważne

  • Ude często myli MacCyrillic z Windows-1251 w plikach cyrylicznych.
  • Heurystyka oparta na 'dziwnych' bajtach poprawia wykrywanie bez zmiany biblioteki.
  • Rozwiązanie działa tylko dla prostego tekstu rosyjskiego.
  • Zaleca się ręczną weryfikację w Notepad++ przed załadowaniem pliku.
  • Prawdopodobieństwowa natura wykrywania kodowania oznacza, że błędy są nieuniknione.

— Editorial Team

Advertisement 728x90

Czytaj dalej