it-swarm-eu.dev

Jak mohu zjistit kódování/kódovou stránku textového souboru

V naší aplikaci přijímáme textové soubory (.txt, .csv atd.) Z různých zdrojů. Při čtení tyto soubory někdy obsahují smetí, protože soubory, které byly vytvořeny v jiné/neznámé kódové stránce.

Existuje způsob, jak (automaticky) detekovat kódovou stránku textového souboru? 

detectEncodingFromByteOrderMarks, v konstruktoru StreamReader, pracuje pro UTF8 a další unicode označené soubory, ale hledám způsob, jak detekovat kódové stránky, jako ibm850, windows1252


Díky za vaše odpovědi, to je to, co jsem udělal.

Soubory, které dostáváme, pocházejí od koncových uživatelů, nemají ponětí o codepages. Přijímače jsou také konečnými uživateli, což je nyní to, co vědí o codepages: Codepages existují a jsou nepříjemné.

Řešení:  

  • Otevřete přijatý soubor v programu Poznámkový blok, podívejte se na zkomolený kus textu. Pokud se někdo jmenuje François nebo něco, s vaší lidskou inteligencí, můžete to odhadnout.
  • Vytvořil jsem malou aplikaci, kterou může uživatel použít k otevření souboru, a zadejte text, který uživatel ví, že se objeví v souboru, když je použita správná kódová stránka. 
  • Projděte si všechny codepages a zobrazte ty, které dávají řešení s uživatelským textem. 
  • Pokud se objeví více jako jedna kódová stránka, požádejte uživatele, aby zadal další text.
283
GvS

Nemůžete detekovat kódovou stránku, musíte jí to říct. Můžete analyzovat bajty a hádat, ale to může dát nějaké bizarní (někdy zábavné) výsledky. Nemůžu to najít teď, ale jsem si jistý, že Poznámkový blok může být podveden do zobrazení anglického textu v čínštině. 

Každopádně je to to, co musíte číst: Absolutní minimum každý vývojář softwaru Absolutně, pozitivně musí vědět o sadách Unicode a znakových sadách (bez výmluv!) .

Konkrétně Joel říká:

Jediný nejdůležitější fakt o kódování

Pokud úplně zapomenete na všechno, co jsem právě vysvětlil, nezapomeňte prosím na jednu mimořádně důležitou skutečnost. Nemá smysl mít řetězec, aniž by věděl, jaké kódování používá. Nemůžete už držet hlavu v písku a předstírat, že "prostý" text je ASCII. Neexistuje žádná taková věc jako prostý text.

Pokud máte řetězec, v paměti, v souboru nebo v e-mailové zprávě, musíte vědět, v jakém kódování se nachází, nebo jej nemůžete správně interpretovat nebo zobrazit uživatelům.

255
JV.

Pokud chcete detekovat ne-UTF kódování (tj. Žádný kusovník), jste v podstatě na heuristiku a statistickou analýzu textu. Možná se budete chtít podívat na dokument Mozilla o detekci univerzální znakové sady ( stejný odkaz, s lepším formátováním přes Wayback Machine ).

30
Tomer Gabel

Vyzkoušeli jste C # port pro Mozilla Universal Charset Detector

Příklad 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.");
        }
    }
}    
21
ITmeze

Nelze zjistit kódovou stránku

To je zjevně nepravdivé. Každý webový prohlížeč má nějaký univerzální charsetový detektor, který se zabývá stránkami, které nemají žádnou známku kódování. Firefox má jeden. Kód si můžete stáhnout a zjistit, jak to dělá. Viz dokumentace zde . V podstatě je to heuristika, ale ta, která funguje opravdu dobře.

Vzhledem k rozumnému množství textu je dokonce možné jazyk rozpoznat.

Zde je další Právě jsem zjistil (a) pomocí Google:

15
shoosh

Vím, že je na tuto otázku velmi pozdě, a toto řešení nebude pro některé z nich žádoucí (kvůli jeho anglicky orientované zaujatosti a nedostatku statistických/empirických testů), ale pro mě to fungovalo velmi dobře, zejména pro zpracování nahraných dat CSV:

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

Výhody:

  • Vestavěná detekce kusovníku
  • Výchozí/záložní kódování lze přizpůsobit
  • docela spolehlivý (podle mých zkušeností) pro západoevropské soubory obsahující exotická data (např. francouzská jména) se směsí souborů ve formátu UTF-8 a Latin-1 - což je v podstatě většina amerických a západoevropských prostředí.

Poznámka: Já jsem ten, kdo napsal tuto třídu, takže to samozřejmě vezměte s obilím soli! :)

8
Tao

Když jsem hledal jiné řešení, zjistil jsem to 

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

toto řešení je trochu těžké.

Potřeboval jsem základní detekci kódování na základě 4 prvních bajtů a pravděpodobně xml charset detekce - tak jsem si vzal nějaký ukázkový zdrojový kód z internetu a přidal trochu upravenou verzi

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

napsaný pro Javu.

    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
    }

Stačí si přečíst asi prvních 1024 bytů ze souboru, ale načítám celý soubor.

7
TarmoPikaro

Notepad ++ má tuto funkci mimo krabici. Podporuje také změnu.

7
hegearon

Pokud někdo hledá 93,9% řešení. To funguje pro mě:

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
Magu

Nástroj "uchardet" to dělá dobře s použitím modelů pro distribuci znakových frekvencí pro každou znakovou sadu. Větší soubory a další "typické" soubory mají větší důvěru (samozřejmě).

Na ubuntu jste právě apt-get install uchardet

Na jiných systémech získáte zdroj, použití a dokumenty zde: https://github.com/BYVoid/uchardet

3
Erik Aronesty

Konstruktor třídy StreamReader má parametr 'detect encoding'.

3
leppie

Pokud můžete odkazovat na knihovnu C, můžete použít libenca. Viz http://cihar.com/software/enca/ . Z manuálové stránky:

Enca čte dané textové soubory, nebo standardní vstup, když žádný není uveden, A používá znalosti o jejich jazyce (musí být podporovány vámi) a Směs analýzy, statistické analýzy, hádání a černé magie k určení jejich kódování.

Je to GPL v2.

1
Kundor

Máte stejný problém, ale nenalezli jste dobré řešení pro jeho automatické rozpoznání. Nyní pomocí programu PsPad (www.pspad.com);

0
DeeCee

Díky @ Erik Aronesty za zmínku uchardet.

Mezitím existuje (stejný?) Nástroj pro linux: chardet.
Nebo na stránce cygwin můžete použít: chardetect.

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

To bude heuristicky detekovat (hádat) kódování znaků pro každý daný soubor a bude hlásit jméno a úroveň důvěryhodnosti kódování každého souboru.

0
Schlacki

Vlastně jsem hledal obecný, ne programovací způsob detekce kódování souboru, ale to jsem ještě nenašel. Co jsem zjistil testováním s různými kódováními bylo, že můj text byl UTF-7.

Takže kde jsem poprvé dělal: StreamReader file = File.OpenText (fullfilename);

Musel jsem to změnit na: StreamReader file = new StreamReader (fullfilename, System.Text.Encoding.UTF7);

OpenText předpokládá, že je to UTF-8.

můžete také vytvořit StreamReader, jako je tento nový StreamReader (fullfilename, true), druhý parametr znamená, že by měl zkusit zjistit kódování z byteordermark souboru, ale to v mém případě nefungovalo.

0
Intraday Tips

Jako addon k ITmeze postu jsem použil tuto funkci pro převod výstupu C # portu pro Mozilla Universal Charset Detector

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

MSDN

0
PrivatePyle

Otevřete soubor v AkelPad (nebo jen zkopírujte/vložte zkomolený text), jděte na Edit -> Selection -> Recode ... -> check "Autodetect".

0
plavozont

Vzhledem k tomu, že jde v podstatě o heuristiku, může pomoci použít kódování dříve přijatých souborů ze stejného zdroje jako první nápověda.

Většina lidí (nebo aplikací) pokaždé dělá věci ve stejném pořadí, často na stejném počítači, takže je velmi pravděpodobné, že když Bob vytvoří soubor CSV a odešle jej Mary, bude vždy používat systém Windows-1252 nebo bez ohledu na to, co jeho stroj nastaví.

Kde je to možné, trochu školení zákazníků nikdy nebolí :-)

0
devstuff

10Y (!) Uplynulo od té doby, co to bylo položeno, a stále nevidím žádnou zmínku o dobrém, ne-GPL 'řešení MS: IMultiLanguage2 API.

Většina již zmíněných knihoven je založena na UDE Mozilly - a zdá se být rozumné, že prohlížeče již podobné problémy řešily. Nevím, co je chromové řešení, ale protože IE 5.0 MS vydaly své a je to:

  1. Bez licenčních problémů typu GPL a podobných licencí,
  2. Podporován a udržován pravděpodobně navždy,
  3. Poskytuje bohatý výstup - všichni platní kandidáti pro kódování/codepages spolu s skóre spolehlivosti,
  4. Překvapivě snadné použití (jedná se o volání jedné funkce).

Je to nativní COM volání, ale tady je nějaká velmi pěkná práce od Carstena Zeumera, který zpracovává interop mess pro použití .net. Tam jsou někteří jiní kolem, ale velká knihovna nedostane pozornost, kterou si zaslouží.

0
Ofek Shilon