Bir metin dosyasının kodlamasını / kod sayfasını nasıl tespit edebilirim


295

Bizim uygulamada, biz metin dosyaları (almak .txt, .csvçeşitli kaynaklardan, vs.). Okurken, bu dosyalar bazen çöp içerir, çünkü farklı / bilinmeyen bir kod sayfasında oluşturulan dosyalar.

Bir metin dosyasının kod sayfasını (otomatik olarak) tespit etmenin bir yolu var mı?

detectEncodingFromByteOrderMarksÜzerinde StreamReaderyapıcı, çalışır UTF8 ve diğer unicode işaretli dosyalar fakat bunun, kod sayfalarını tespit etmek için bir yol arıyorum ibm850, windows1252.


Cevaplarınız için teşekkürler, yaptığım şey bu.

Aldığımız dosyalar son kullanıcılardan, kod sayfaları hakkında bir ipucu yok. Alıcılar da son kullanıcı, şimdiye kadar kod sayfaları hakkında bildikleri şey bu: Kod sayfaları var ve sinir bozucu.

Çözüm:

  • Alınan dosyayı Not Defteri'nde açın, bozuk bir metin parçasına bakın. Eğer birine François falan denirse, insan zekanızla bunu tahmin edebilirsiniz.
  • Kullanıcının dosyayı açmak için kullanabileceği küçük bir uygulama oluşturdum ve doğru kod sayfası kullanıldığında kullanıcının dosyada görüneceğini bildiği bir metin girdim.
  • Tüm kod sayfalarında dolaşın ve kullanıcı tarafından sağlanan metinle çözüm sağlayanları görüntüleyin.
  • Birden fazla kod sayfası açılırsa kullanıcıdan daha fazla metin belirtmesini isteyin.

Yanıtlar:


260

Kod sayfasını tespit edemezsiniz, size söylenmelidir. Baytları analiz edebilir ve tahmin edebilirsiniz, ancak bu bazı tuhaf (bazen eğlenceli) sonuçlar verebilir. Şimdi bulamıyorum, ama eminim Not Defteri Çince metin görüntülemek için kandırılabilir.

Her neyse, bu okumanız gereken şey: Mutlak Minimum Her Yazılım Geliştiricisi Kesinlikle, Olumlu Unicode ve Karakter Kümeleri Hakkında Bilmelisiniz (Bahane Yok!) .

Özellikle Joel diyor ki:

Kodlamalar Hakkında En Önemli Gerçek

Açıkladığım her şeyi tamamen unutursanız, lütfen son derece önemli bir gerçeği unutmayın. Hangi kodlamayı kullandığını bilmeden bir dizeye sahip olmak mantıklı değildir. Artık kafanı kuma sokamaz ve "düz" metnin ASCII olduğunu iddia edemezsin. Düz Metin diye bir şey yoktur.

Dizede, bellekte, dosyada veya e-posta iletisinde bir dize varsa, kodlamanın içinde olduğunu bilmeniz gerekir veya onu yorumlayamaz veya kullanıcılara doğru görüntüleyemezsiniz.


43
Bu cevabı iki nedenden dolayı reddettim. İlk olarak, "anlatılmak gerekir" demek işe yaramaz. Bana kim söyleyecekti ve hangi ortam aracılığıyla yapacaklardı? Dosyayı kurtaran ben olsaydım, kime sorardım? Kendim? İkinci olarak, makale soruyu cevaplamak için bir kaynak olarak özellikle yararlı değildir. Makale daha çok David Sedaris tarzında yazılmış bir kodlama öyküsüdür. Anlatıyı takdir ediyorum, ancak soruyu basitçe / doğrudan cevaplamıyor.
geneorama

9
@ geneorama, sanırım Joel'in makalesi sorularınızı her zamankinden daha iyi ele alıyor, ama işte gidiyor ... Araç kesinlikle metnin alındığı ortama bağlı. Daha iyi dosya (ya da ne olursa olsun) bu bilgileri içeriyor (Ben HTML ve XML düşünüyorum). Aksi takdirde, metni gönderen kişinin bu bilgiyi vermesine izin verilmelidir. Dosyayı oluşturan sizseniz, hangi kodlamayı kullandığını nasıl bilemezsiniz?
JV.

4
@geneorama, devam etti ... Son olarak, makalenin soruyu cevaplamamasının ana sebebinin bu soruya basit bir cevap olmaması nedeniyle sanırım. Eğer soru "Nasıl tahmin edebilirim ki ..." olsaydı farklı cevaplar verirdim.
JV.

1
@JV Daha sonra xml / html'in karakter kodlamasını belirleyebildiğini öğrendim, bu kullanışlı tidbit'ten bahsettiğiniz için teşekkürler.
geneorama

1
@JV "Dosya oluştur" kelimelerin kötü bir seçimi olabilir. Bir kullanıcının, kullanıcının oluşturduğu bir dosyanın kodlamasını belirtebileceğini varsayıyorum. Son zamanlarda bir Hadoop Kümesi'nden Hive kullanarak bir dosya "oluşturdum" ve çeşitli istemci makinelere indirmeden önce bir FTP'ye geçtim. Sonuçta bazı unicode çöpler vardı, ancak hangi adımın sorunu yarattığını bilmiyorum. Kodlamayı hiç belirtmedim. Her adımda kodlamayı kontrol edebilseydim.
geneorama

31

UTF olmayan kodlamaları (yani BOM yok) tespit etmek istiyorsanız, temel olarak metnin sezgisel tarama ve istatistiksel analizine bağlısınız. Evrensel karakter kümesi algılama ile ilgili Mozilla makalesine göz atmak isteyebilirsiniz ( Wayback Machine ile daha iyi biçimlendirme ile aynı bağlantı ).


9
Ne yazık ki Firefox 3.05 kurulumum, kaynağın Windows-1252 için bir meta etikete sahip olmasına rağmen, bu sayfayı UTF-8 olarak algılıyor ve bir dizi elmas-içinde-işaret glifi gösteriyor. Karakter kodlamasını elle değiştirmek belgeyi doğru bir şekilde gösterir.
devstuff

5
"UTF olmayan kodlamaları (yani BOM yok) tespit etmek istiyorsanız" cümleniz biraz yanıltıcıdır; unicode standardı utf-8 belgelerine ürün ağacı eklemenizi önermez! (ve bu öneri veya eksikliği birçok baş ağrısının kaynağıdır). ref: en.wikipedia.org/wiki/Byte_order_mark#UTF-8
Tao

Bu, gereksiz malzeme listelerini biriktirmeden UTF-8 dizelerini birleştirebilmeniz için yapılır. Ayrıca, örneğin UTF-16'dan farklı olarak, UTF-8 için bir Bayt Sırası İşaretine gerek yoktur.
sashoalm

26

Mozilla Universal Charset Detector için C # portunu denediniz mi?

Http://code.google.com/p/ude/ adresinden bir örnek

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

1
Windows-1252 tipi için kusursuz çalıştı.
seebiscuit

Ve bunu kullanarak bir metin dosyasını okumak için nasıl kullanabilirsiniz? CharsetDetector kodlamanın adını dize biçiminde döndürür ve hepsi bu kadar ...
Bartosz

@Bartoszprivate Encoding GetEncodingFromString(string encoding) { try { return Encoding.GetEncoding(encoding); } catch { return Encoding.ASCII; } }
PrivatePyle

15

Kod sayfasını tespit edemezsiniz

Bu açıkça yanlış. Her web tarayıcısında herhangi bir kodlama belirtisi olmayan sayfalarla uğraşmak için bir tür evrensel karakter dedektörü vardır. Firefox'ta bir tane var. Kodu indirebilir ve nasıl yaptığını görebilirsiniz. Buradaki bazı belgelere bakın . Temel olarak, sezgisel, ama gerçekten iyi çalışan biri.

Makul miktarda metin verildiğinde, dili algılamak bile mümkündür.

İşte Google'ı kullanarak yeni bulduğum bir tane daha :


39
"sezgisel tarama" - bu yüzden tarayıcı onu tam olarak algılamıyor, eğitimli bir tahmin yapıyor. "gerçekten iyi çalışıyor" - o zaman her zaman işe yaramıyor? Anlaştığımız gibi geliyor bana.
JV.

10
HTML standardı, karakter kümesi belge tarafından tanımlanmadıysa, UTF-8 olarak kodlanmış olarak kabul edilmesi gerektiğini belirtir.
Jon Trauntvein

5
Standart olmayan HTML belgelerini okumadığımız sürece bu iyidir. Veya HTML olmayan belgeler.
Kos

2
Bu cevap yanlış, bu yüzden aşağı indirmek zorunda kaldım. Kod sayfasını tespit edememenizin yanlış olacağını söylemek yanlıştır. Tahmin edebilirsiniz ve tahminleriniz oldukça iyi olabilir, ancak bir kod sayfasını "tespit edemez".
z80crew

1
@JonTrauntvein HTML5 spesifikasyonlarına göre a character encoding declaration is required even if the encoding is US-ASCII - eksik bir bildirim UTF8'e geri dönmemek için bir sezgisel algoritma kullanmakla sonuçlanır.
z80crew

9

Bu soru için çok geç olduğunu biliyorum ve bu çözüm bazılarına hitap etmeyecek (İngiliz merkezli önyargıları ve istatistiksel / ampirik test eksikliği nedeniyle), ancak özellikle yüklenen CSV verilerini işlemek için benim için çok iyi çalıştı:

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

Avantajları:

  • Dahili BOM algılama
  • Varsayılan / yedek kodlama özelleştirilebilir
  • UTF-8 ve Latin-1 tarzı dosyaların bir karışımı ile bazı egzotik veriler (örneğin Fransız isimleri) içeren batı-avrupa tabanlı dosyalar için oldukça güvenilirdir (benim deneyimime göre) - temel olarak ABD ve batı avrupa ortamlarının büyük bir kısmı.

Not: Bu sınıfı yazan kişi benim, bu yüzden açıkça bir tane tuzla al! :)



7

Farklı bir çözüm arıyorum, buldum ki

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

bu çözüm biraz ağırdır.

Ben 4 ilk bayt ve muhtemelen xml charset algılama dayalı bazı temel kodlama algılama gerekli - bu yüzden internetten bazı örnek kaynak kodu aldı ve biraz değiştirilmiş sürümü ekledim

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

Java için yazılmıştır.

    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
    }

Muhtemelen ilk 1024 baytı dosyadan okumak yeterlidir, ancak tüm dosyayı yüklüyorum.


7

Birisi% 93.9'luk bir çözüm arıyorsa. Bu benim için çalışıyor:

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

Çok güzel bir çözüm. 2'den fazla kodlamaya (UTF-8 ve ASCI 1252) izin verilmesi gerekiyorsa, ReadAsString () gövdesini izin verilen kodlama döngüsüne kolayca sarın.
ViRuSTriNiTy

Tonlarca örnek denedikten sonra nihayet seninkine geldim. Şu anda mutlu bir yerdeyim. lol Teşekkürler !!!!!!!
Sedrick

Bu, 1252 ve 1250'nin nasıl tespit edileceğinin cevabı olmayabilir, ancak kesinlikle bir Malzeme Listesi ile veya olmadan "UTF-8 nasıl tespit edilir" cevabı olmalıdır!
chuckc

4

Python'da benzer bir şey yaptım. Temel olarak, kayan iki baytlık bir pencere tarafından parçalanan ve bir sözlükte (karma) saklanan, kodlama listelerinin değerlerini sağlayan bayt çiftlerine anahtarlanan çeşitli kodlamalardan çok sayıda örnek verilere ihtiyacınız vardır.

Sözlüğün (karma) verildiği takdirde, giriş metninizi alırsınız ve:

  • herhangi bir BOM karakteriyle başlarsa (UTF-16-BE için '\ xfe \ xff', UTF-16-LE için '\ xff \ xfe', UTF-8 vb için '\ xef \ xbb \ xbf'), I önerildiği gibi davran
  • değilse, metnin yeterince büyük bir örneğini alın, örneğin tüm bayt çiftlerini alın ve sözlükten önerilen en az yaygın olan kodlamayı seçin.

Ayrıca do UTF kodlanmış metinleri örneklenmiş ettiyseniz değil herhangi BOM ile başlamak, ikinci aşama ilk adımdan kaymış olanlar kapsayacaktır.

Şimdiye kadar, azalan hata oranları ile benim için çalışıyor (örnek veriler ve sonraki giriş verileri çeşitli dillerde altyazılar).


4

"Uchardet" aracı her karakter için karakter frekansı dağıtım modellerini kullanarak bunu iyi yapar. Daha büyük dosyalar ve daha "tipik" dosyalar daha fazla güvendeler.

Ubuntu'da, sadece apt-get install uchardet.

Diğer sistemlerde kaynağı, kullanımı ve dokümanları buradan edinebilirsiniz: https://github.com/BYVoid/uchardet


Homebrew üzerinden Mac'te:brew install uchardet
Paul B

3

StreamReader sınıfının yapıcısı 'kodlamayı algıla' parametresini alır.


Burada sadece "kodlama" bağlantısı .. ve açıklama Kodlama sağlamak zorundayız diyor ..
SurajS

@SurajS: Diğer aşırı yüklenmelere bakın.
leppie

orijinal yazar potansiyel olarak BOM İşaretçisi olmayan bir dosyanın kodlamasını tespit etmek ister. StreamReader imza başına BOM Üstbilgisinden kodlama algılar. public StreamReader (Akış akışı, bool algılamaEncodingFromByteOrderMarks)
ibondre

1

Bir C kütüphanesine bağlanabiliyorsanız kullanabilirsiniz libenca. Bkz. Http://cihar.com/software/enca/ . Man sayfasından:

Enca, hiçbiri verilmediğinde verilen metin dosyalarını veya standart girdiyi okur ve kodlarını belirlemek için kendi dilleri (sizin tarafınızdan desteklenmesi gerekir) ve ayrıştırma, istatistiksel analiz, tahmin ve kara büyü karışımı kullanır.

Bu GPL v2.


0

Aynı sorunu var ama otomatik olarak tespit etmek için henüz iyi bir çözüm bulamadı. Şimdi bunun için PsPad (www.pspad.com) kullanarak im;) iyi çalışıyor


0

Temel olarak buluşsal yöntemlere geldiğinden, daha önce alınan dosyaların ilk ipucu ile aynı kaynaktan kodlanmasını kullanmak yardımcı olabilir.

Çoğu kişi (veya uygulama) her seferinde hemen hemen aynı sırada, genellikle aynı makinede işler yapar, bu yüzden Bob bir .csv dosyası oluşturup Mary'ye gönderdiğinde her zaman Windows-1252 veya makine varsayılanı ne olursa olsun.

Mümkünse biraz müşteri eğitimi de asla acıtmaz :-)


0

Aslında dosya kodlamasını saptamanın genel bir programlama yolu değil, ama henüz bulamadım. Farklı kodlamalar ile test ederek bulduğum şey, metnimin UTF-7 olmasıydı.

Yani ilk yaptığım yerde: StreamReader file = File.OpenText (fullfilename);

Bunu değiştirmek zorunda kaldım: StreamReader dosyası = yeni StreamReader (fullfilename, System.Text.Encoding.UTF7);

OpenText, UTF-8 olduğunu varsayar.

StreamReader'ı bu yeni StreamReader (fullfilename, true) gibi de oluşturabilirsiniz, ikinci parametre, dosyanın byteordermarkinden kodlamayı denemesi ve algılaması gerektiği anlamına gelir, ancak benim durumumda işe yaramadı.


@JohnMachin Nadir olduğunu kabul ediyorum, ancak IMAP protokolünün bazı kısımlarında zorunlu kılınmıştır. Eğer bulunduğunuz yer buysa, tahmin etmek zorunda kalmazsınız.
üçlü

0

AkelPad'de dosyayı açın (veya sadece bozuk bir metni kopyalayıp yapıştırın), Düzenle -> Seçim -> Yeniden kodla ... -> "Otomatik Algıla" yı işaretleyin.


0

ITmeze yazısına ek olarak, bu işlevi Mozilla Universal Charset Detector için C # portunun çıkışını dönüştürmek için kullandım

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

MSDN



-1

Bir dosyayı okurken Unicode ve windows varsayılan ansi kod sayfasını algılamak için bu kodu kullanın. Diğer kodlamalar için, manuel olarak veya programlama yoluyla içerik kontrolü gereklidir. Bu, metni açıldığı zamanki kodlamayla kaydetmek için de kullanılabilir. (VB.NET kullanıyorum)

'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()

-1

Bu sorulduğundan beri 10Y (!) Geçmişti ve hala MS'in iyi, GPL olmayan çözümü: IMultiLanguage2 API'sından bahsetmiyorum .

Daha önce bahsedilen kütüphanelerin çoğu Mozilla'nın UDE'sine dayanmaktadır - ve tarayıcıların zaten benzer sorunları çözdüğü makul görünmektedir. Chrome'un çözümü nedir bilmiyorum, ama IE 5.0 MS kendi yayınladı beri ve o:

  1. GPL ve benzeri lisanslama sorunları içermez,
  2. Muhtemelen sonsuza dek desteklenmeli ve korunmalı,
  3. Zengin çıktılar verir - güven puanlarıyla birlikte kodlama / kod sayfaları için tüm geçerli adaylar,
  4. Şaşırtıcı derecede kullanımı kolay (tek bir işlev çağrısıdır).

Yerel bir COM çağrısıdır, ancak işte Carsten Zeumer'ın .net kullanımı için birlikte çalışabilirlik karmaşasını ele alan çok güzel bir çalışma . Etrafında başkaları da var, ancak bu kütüphane genel olarak hak ettiği ilgiyi görmüyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.