Jak mogę wykryć kodowanie / kodowanie pliku tekstowego

W naszej aplikacji otrzymujemy pliki tekstowe (.txt, .csv, itd.) z różnych źródeł. Podczas odczytu pliki te czasami zawierają śmieci, ponieważ pliki, w których utworzono inną / nieznaną stronę kodową.

Czy istnieje sposób na (automatyczne) wykrycie strony kodowej pliku tekstowego?

detectEncodingFromByteOrderMarks, na konstruktorze StreamReader, działa dla UTF8 i innych plików oznaczonych unicode, ale szukam sposobu na wykrywanie stron kodowych, takich jakibm850, windows1252.


Thanks for your odpowiedzi, To właśnie zrobiłem.

Pliki, które otrzymujemy są od użytkowników końcowych, nie mają pojęcia o stronach kodowych. Odbiorniki są również użytkownikami końcowymi, już to wiedzą o stronach kodowych: strony kodowe istnieją i są denerwujące.

Rozwiązanie:

  • Otwórz odebrany plik w Notatniku, spójrz na zniekształcony fragment tekstu. Jeśli ktoś ma na imię François czy coś, z Twoją ludzką inteligencją możesz to odgadnąć.
  • stworzyłem małą aplikację, która użytkownik może użyć do otwarcia pliku i wprowadzić tekst, który użytkownik wie, że pojawi się w pliku, gdy używana jest prawidłowa strona kodowa.
  • przejrzyj wszystkie strony kodowe i wyświetl te, które dają rozwiązanie z tekstem dostarczonym przez użytkownika.
  • Jeśli pojawi się więcej jako jedna strona kodowa, Poproś użytkownika o podanie większej ilości tekstu.
Author: james.garriss, 2008-09-18

20 answers

Nie możesz wykryć strony kodowej, musisz to powiedzieć. Można analizować bajty i zgadywać, ale to może dać dziwne (czasami zabawne) wyniki. Nie mogę go teraz znaleźć, ale jestem pewien, że Notatnik można oszukać do wyświetlania angielskiego tekstu w Języku Chińskim.

W każdym razie, to jest to, co trzeba przeczytać: absolutne Minimum każdy programista absolutnie, pozytywnie musi wiedzieć o Unicode i zestawach znaków (bez wymówek!).

Konkretnie Joel says:

Najważniejszy Fakt O Kodowaniu

Jeśli całkowicie zapomnisz o wszystkim, co właśnie wyjaśniłem, pamiętaj o jednym niezwykle ważnym fakcie. Nie ma sensu mieć ciąg znaków bez wiedzy, jakiego kodowania używa. Nie możesz już wkładać głowy w piasek i udawać, że" zwykły " tekst jest ASCII. Nie ma czegoś takiego jak zwykły tekst.

Jeśli masz ciąg znaków, w pamięci, w pliku lub w wiadomości e-mail, musisz wiedzieć, co kodowanie jest w lub nie można go poprawnie zinterpretować lub wyświetlić użytkownikom.

 252
Author: JV.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-11 08:12:59

Jeśli chcesz wykryć kodowanie nie-UTF (tj. brak BOM), w zasadzie sprowadzasz się do heurystyki i analizy statystycznej tekstu. Możesz rzucić okiem na Artykuł Mozilli na temat wykrywania uniwersalnych znaków (ten sam link, z lepszym formatowaniem przez Wayback Machine ).

 30
Author: Tomer Gabel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-09 17:25:01

Czy próbowałeś C# port dla Mozilla Universal Charset Detector

Przykład z http://code.google.com/p/ude/

public static void Main(String[] args)
{
    string filename = args[0];
    using (FileStream fs = File.OpenRead(filename)) {
        Ude.CharsetDetector cdet = new Ude.CharsetDetector();
        cdet.Feed(fs);
        cdet.DataEnd();
        if (cdet.Charset != null) {
            Console.WriteLine("Charset: {0}, confidence: {1}", 
                 cdet.Charset, cdet.Confidence);
        } else {
            Console.WriteLine("Detection failed.");
        }
    }
}    
 20
Author: ITmeze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-23 10:47:38

nie możesz wykryć strony kodowej

To jest ewidentnie fałszywe. Każda przeglądarka internetowa ma jakiś uniwersalny wykrywacz znaków, który radzi sobie ze stronami, które nie mają żadnego wskazania kodowania. Firefox ma jeden. Możesz pobrać kod i zobaczyć, jak to robi. Zobacz dokumentację tutaj . Zasadniczo jest to heurystyka, ale działa naprawdę dobrze.

Biorąc pod uwagę rozsądną ilość tekstu, możliwe jest nawet wykrycie język.

Oto kolejny , który właśnie znalazłem za pomocą Google:

 15
Author: shoosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-08 17:30:48

Wiem, że jest bardzo późno na to pytanie i to rozwiązanie nie spodoba się niektórym( ze względu na jego stronniczość anglocentryczną i brak badań statystycznych/empirycznych), ale działało bardzo dobrze dla mnie, szczególnie przy przetwarzaniu przesłanych danych CSV: {]}

Http://www.architectshack.com/TextFileEncodingDetector.ashx

Zalety:

  • wbudowane wykrywanie BOM
  • domyślne / awaryjne kodowanie konfigurowalne
  • całkiem wiarygodne (z mojego doświadczenia) dla zachodnioeuropejskie pliki zawierające egzotyczne dane (np. Francuskie nazwy) z mieszaniną plików w stylu UTF-8 i Latin-1 - w zasadzie większość środowisk amerykańskich i zachodnioeuropejskich.

Uwaga: To ja napisałem tę klasę, więc oczywiście weź to z przymrużeniem oka! :)

 8
Author: Tao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-29 09:20:17

Notepad++ posiada tę funkcję po wyjęciu z pudełka. Wspiera również jego zmianę.

 7
Author: hegearon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-18 00:10:35

Szukając innego rozwiązania, znalazłem, że

Https://code.google.com/p/ude/

To rozwiązanie jest dość ciężkie.

Potrzebowałem podstawowej detekcji kodowania, opartej na 4 pierwszych bajtach i prawdopodobnie wykrywaniu znaków XML - więc pobrałem przykładowy kod źródłowy z Internetu i dodałem nieco zmodyfikowaną wersję

Http://lists.w3.org/Archives/Public/www-validator/2002Aug/0084.html

Napisane dla Javy.

    public static Encoding DetectEncoding(byte[] fileContent)
    {
        if (fileContent == null)
            throw new ArgumentNullException();

        if (fileContent.Length < 2)
            return Encoding.ASCII;      // Default fallback

        if (fileContent[0] == 0xff
            && fileContent[1] == 0xfe
            && (fileContent.Length < 4
                || fileContent[2] != 0
                || fileContent[3] != 0
                )
            )
            return Encoding.Unicode;

        if (fileContent[0] == 0xfe
            && fileContent[1] == 0xff
            )
            return Encoding.BigEndianUnicode;

        if (fileContent.Length < 3)
            return null;

        if (fileContent[0] == 0xef && fileContent[1] == 0xbb && fileContent[2] == 0xbf)
            return Encoding.UTF8;

        if (fileContent[0] == 0x2b && fileContent[1] == 0x2f && fileContent[2] == 0x76)
            return Encoding.UTF7;

        if (fileContent.Length < 4)
            return null;

        if (fileContent[0] == 0xff && fileContent[1] == 0xfe && fileContent[2] == 0 && fileContent[3] == 0)
            return Encoding.UTF32;

        if (fileContent[0] == 0 && fileContent[1] == 0 && fileContent[2] == 0xfe && fileContent[3] == 0xff)
            return Encoding.GetEncoding(12001);

        String probe;
        int len = fileContent.Length;

        if( fileContent.Length >= 128 ) len = 128;
        probe = Encoding.ASCII.GetString(fileContent, 0, len);

        MatchCollection mc = Regex.Matches(probe, "^<\\?xml[^<>]*encoding[ \\t\\n\\r]?=[\\t\\n\\r]?['\"]([A-Za-z]([A-Za-z0-9._]|-)*)", RegexOptions.Singleline);
        // Add '[0].Groups[1].Value' to the end to test regex

        if( mc.Count == 1 && mc[0].Groups.Count >= 2 )
        {
            // Typically picks up 'UTF-8' string
            Encoding enc = null;

            try {
                enc = Encoding.GetEncoding( mc[0].Groups[1].Value );
            }catch (Exception ) { }

            if( enc != null )
                return enc;
        }

        return Encoding.ASCII;      // Default fallback
    }

It ' s enough to odczytam prawdopodobnie pierwsze 1024 bajty z pliku, ale Ładuję cały plik.

 7
Author: TarmoPikaro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-19 16:23:31

Jeśli ktoś szuka rozwiązania na 93,9%. To mi działa:

public static class StreamExtension
{
    /// <summary>
    /// Convert the content to a string.
    /// </summary>
    /// <param name="stream">The stream.</param>
    /// <returns></returns>
    public static string ReadAsString(this Stream stream)
    {
        var startPosition = stream.Position;
        try
        {
            // 1. Check for a BOM
            // 2. or try with UTF-8. The most (86.3%) used encoding. Visit: http://w3techs.com/technologies/overview/character_encoding/all/
            var streamReader = new StreamReader(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), detectEncodingFromByteOrderMarks: true);
            return streamReader.ReadToEnd();
        }
        catch (DecoderFallbackException ex)
        {
            stream.Position = startPosition;

            // 3. The second most (6.7%) used encoding is ISO-8859-1. So use Windows-1252 (0.9%, also know as ANSI), which is a superset of ISO-8859-1.
            var streamReader = new StreamReader(stream, Encoding.GetEncoding(1252));
            return streamReader.ReadToEnd();
        }
    }
}
 5
Author: Magu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-09 14:50:20

Zrobiłem coś podobnego w Pythonie. Zasadniczo, potrzebujesz wiele przykładowych danych z różnych kodowań, które są podzielone przez przesuwane dwubajtowe okno i przechowywane w słowniku( hash), kluczowanym na parach bajtów dostarczających wartości list kodowań.

Biorąc pod uwagę ten słownik (hash), bierzesz swój tekst wejściowy i:

  • jeśli zaczyna się od dowolnego znaku BOM ('\xfe\xff ' dla UTF-16-BE, '\xff\xfe' dla UTF-16-LE, '\xef\xbb\xbf' dla UTF-8 itd.), traktuję to jako suggested
  • jeśli nie, to weź wystarczająco dużą próbkę tekstu, weź wszystkie pary bajtów próbki i wybierz kodowanie, które jest najmniej powszechne sugerowane ze słownika.

Jeśli próbkowałeś również tekstów kodowanych UTF, które nie zaczynają się od dowolnego BOM, drugi krok obejmie te, które wyszły z pierwszego kroku.

Jak na razie działa u mnie (przykładowe dane i kolejne dane wejściowe są napisami w różnych językach) z malejącym błędem stawki.

 4
Author: tzot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 09:03:38

Konstruktor klasy StreamReader pobiera parametr 'detect encoding'.

 3
Author: leppie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 08:04:28

Narzędzie "uchardet" robi to dobrze, używając modeli rozkładu częstotliwości znaków dla każdego zestawu znaków. Większe pliki i bardziej" typowe " pliki mają większą pewność (oczywiście).

Na ubuntu, po prostu apt-get install uchardet.

Na innych systemach Pobierz źródło, użycie i dokumenty tutaj: https://github.com/BYVoid/uchardet

 3
Author: Erik Aronesty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-03 14:20:41

Jeśli możesz połączyć się z biblioteką C, możesz użyć libenca. Zobacz http://cihar.com/software/enca/. ze strony man:

Enca odczytuje podane pliki tekstowe lub standardowe wejście, gdy nie podano, i wykorzystuje wiedzę na temat ich języka (musi być przez Ciebie poparta) i mieszanka parsowania, analizy statystycznej, zgadywania i czarnej magii aby określić ich kodowanie.

To GPL v2.

 1
Author: Kundor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-27 03:25:12

Mam ten sam problem, ale nie znalazłem jeszcze dobrego rozwiązania do wykrywania go automatycznie . Teraz używam Pspada (www.pspad.com) za to;) działa dobrze

 0
Author: DeeCee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 08:25:40

Ponieważ sprowadza się to zasadniczo do heurystyki, może pomóc użycie kodowania wcześniej otrzymanych plików z tego samego źródła jako pierwszej podpowiedzi.

Większość ludzi (lub aplikacji) robi rzeczy w prawie tej samej kolejności za każdym razem, często na tej samej maszynie, więc jest całkiem prawdopodobne, że gdy Bob tworzy .plik csv i wysyła go do Mary zawsze będzie używać Windows-1252 lub cokolwiek jego maszyna domyślnie.

W miarę możliwości trochę szkolenia klienta też nigdy nie zaszkodzi: -)

 0
Author: devstuff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-29 19:42:00

Szukałem ogólnego, a nie programowego sposobu wykrywania kodowania plików, ale tego jeszcze nie znalazłem. To, co odkryłem testując różne kodowania, to to, że mój tekst to UTF-7.

Więc gdzie po raz pierwszy robiłem: StreamReader file = Plik.OpenText (fullfilename);

Musiałem zmienić na: StreamReader file = new StreamReader (fullfilename, System.Tekst.Kodowanie.UTF7);

OpenText zakłada, że to UTF-8.

Możesz również utworzyć StreamReader jak to nowy StreamReader( fullfilename, true), drugi parametr oznaczający, że powinien próbować wykryć kodowanie z znaku bajtowego pliku, ale to nie zadziałało w moim przypadku.

 0
Author: Intraday Tips,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-25 06:59:32

Otwórz plik w AkelPad(lub po prostu skopiuj / wklej zniekształcony tekst) , przejdź do Edit - > Selection - > Recode... - >zaznacz "autodetekcja".

 0
Author: plavozont,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-22 03:02:43

Jako dodatek do itmeze post, użyłem tej funkcji do konwersji wyjścia portu C# dla Mozilla Universal Charset Detector

    private Encoding GetEncodingFromString(string codePageName)
    {
        try
        {
            return Encoding.GetEncoding(codePageName);
        }
        catch
        {
            return Encoding.ASCII;
        }
    }

MSDN

 0
Author: PrivatePyle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-30 20:54:21

Thanks @Erik Aronesty for mentioning uchardet.

Tymczasem (to samo?) narzędzie istnieje dla Linuksa: chardet.
Na cygwinie możesz też użyć: chardetect.

Zobacz: Strona man chardet: https://www.commandlinux.com/man-page/man1/chardetect.1.html

To heurystycznie wykryje (odgadnie) kodowanie znaków dla każdego podanego pliku i zgłosi nazwę i poziom ufności dla każdego wykrytego kodowania znaków.

 0
Author: Schlacki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-07 12:26:08

10Y (!) minęło, odkąd o to zapytano, i nadal nie widzę wzmianki o dobrym, Nie zgodnym z GPL rozwiązaniu MS: IMULTILANGUAGE2 API.

Większość wymienionych bibliotek opiera się na UDE Mozilli - i wydaje się rozsądne, że przeglądarki już rozwiązały podobne problemy. Nie wiem co to jest rozwiązanie chrome, ale skoro IE 5.0 ms wydało swoje i jest:

  1. Wolne od licencji GPL i podobnych,
  2. poparte i utrzymane prawdopodobnie forever,
  3. daje rich output - wszystkie poprawne kandydatury do kodowania / kodowania stron wraz z wynikami zaufania,
  4. zaskakująco łatwy w użyciu (jest to jedno wywołanie funkcji).

Jest to natywne wywołanie COM, ale Oto bardzo dobra praca autorstwa Carstena Zeumera, która obsługuje bałagan interop dla.Net. Są inni, ale ogólnie ta biblioteka nie zwraca na siebie uwagi, na którą zasługuje.

 0
Author: Ofek Shilon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-04 11:34:33

Używam tego kodu do wykrywania Unicode i domyślnej strony kodowej ANSI systemu windows podczas czytania pliku. W przypadku innych kodowań konieczne jest sprawdzenie zawartości, ręcznie lub przez programowanie. To może de używane do zapisu tekstu z tym samym kodowaniem, jak gdy został otwarty. (Używam VB.NET)

'Works for Default and unicode (auto detect)
Dim mystreamreader As New StreamReader(LocalFileName, Encoding.Default) 
MyEditTextBox.Text = mystreamreader.ReadToEnd()
Debug.Print(mystreamreader.CurrentEncoding.CodePage) 'Autodetected encoding
mystreamreader.Close()
 -2
Author: Thommy Johansson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-27 18:13:31