281

私たちのアプリケーションでは、テキストファイルを受け取ります(.txt.csv、など)さまざまなソースから。ファイルを読むときに、これらのファイルにゴミが含まれることがあります。これは、ファイルが別の未知のコードページで作成されたためです。

テキストファイルのコードページを(自動的に)検出する方法はありますか?

detectEncodingFromByteOrderMarks上のStreamReaderコンストラクタ、のために働くUTF8と他のUnicodeマークのファイルが、私はのようなコードページを検出する方法を探しています、ibm850windows1252


あなたの答えをありがとう、これは私がしたことです。

私たちが受け取るファイルはエンドユーザーからのものです、彼らはコードページについての手がかりを持っていません。レシーバーもエンドユーザーであり、今ではコードページについて知っていることです。コードページは存在し、迷惑です。

溶液:

  • 受け取ったファイルをメモ帳で開き、文字化けしたテキストを見てください。誰かがフランソワか何かと呼ばれるならば、あなたの人間の知性であなたはこれを推測することができます。
  • ユーザーがファイルを開くのに使用できる小さなアプリを作成し、正しいコードページが使用されている場合はファイルに表示されることをユーザーが知っているテキストを入力します。
  • すべてのコードページをループ処理し、ユーザーが提供したテキストを使用して解決策を提供するコードページを表示します。
  • 複数のコードページが表示される場合は、テキストをさらに指定するようにユーザーに依頼してください。

20 답변


252

あなたはコードページを検出することができません、あなたはそれを言われる必要があります。あなたはバイトを分析してそれを推測することができます、しかしそれはいくつかの奇妙な(時には面白い)結果を与えることができます。私は今それを見つけることができません、しかし私はメモ帳が中国語で英語のテキストを表示することにだまされることができると確信しています。

とにかく、これはあなたが読む必要があるものです:絶対最低限すべてのソフトウェア開発者は絶対に、確実にUnicodeと文字セットについて知っていなければなりません(言い訳はしないでください)。

具体的にジョエルは言う:

エンコーディングについての最も重要な事実

あなたが私が今説明したことすべてを完全に忘れるならば、一つの非常に重要な事実を覚えておいてください。どのエンコーディングを使用しているのかを知らずに文字列を取得しても意味がありません。あなたはもはやあなたの頭を砂の中に突き刺すことはできず、そして「普通の」テキストはASCIIであると偽ることはできません。   プレーンテキストのようなものはありません。

文字列、メモリ内、ファイル内、または電子メールメッセージ内に文字列がある場合は、その文字列がどのようなエンコーディングであるかを知る必要があります。そうしないと、解釈できないか、正しく表示できません。


  • それを見つけた:en.wikipedia.org/wiki/Bush_hid_the_facts - JV.
  • 私はこの答えを2つの理由で下げた。まず、「あなたは告げられる必要がある」と言っています。役に立ちません。誰が私に言うだろう、そして彼らはどのような媒体を通してそうするだろうか?ファイルを保存した人の場合、誰に尋ねますか。私自身?第二に、この記事は質問に答えるための資料として特に役に立ちません。この記事は、David Sedarisスタイルで書かれたエンコーディングの歴史の詳細です。私は物語に感謝します、しかしそれは単に/直接質問に答えません。 - geneorama
  • @geneorama、Joelの記事は私がこれまで以上にあなたの質問に取り組むと思いますが、ここに行きます...媒体は確かにテキストが受け取られる環境に依存します。ファイル(またはその他)にその情報が含まれていることをお勧めします(私はHTMLとXMLを考えています)。そうでなければ、テキストを送る人はその情報を供給することを許されるべきです。あなたがファイルを作成した人であれば、どのようにそれがどのエンコーディングを使っているのかわからないのですか? - JV.
  • @geneorama、続き...最後に、この記事で質問に答えられない主な理由は、その質問に対する簡単な答えがないからです。質問が「どうしたらいいですか...」だった場合それなら私は違う答えをしたでしょう。 - JV.
  • @JV私は後でxml / htmlが文字エンコーディングを指定できることを学びました、その便利な一口に言及してくれてありがとう。 - geneorama

30

非UTFエンコーディング(つまりBOMがない)を検出しようとしているなら、基本的にはテキストの発見的方法と統計的分析にかかっています。あなたが見てみたいかもしれませんユニバーサル文字セット検出に関するMozillaの論文Wayback Machineによるより良いフォーマットで、同じリンク


  • おかしなことに、私のFirefox 3.05インストールはそのページをUTF-8として検出し、たくさんの疑問符のひし形のグリフを表示しますが、ソースにはWindows-1252用のメタタグがあります。手動で文字エンコードを変更しても、ドキュメントは正しく表示されます。 - devstuff
  • あなたの文章「あなたが非UTFエンコーディングを検出しようとしている場合(つまりBOMがない場合)」少し誤解を招く可能性があります。 Unicode標準では、UTF-8ドキュメントにBOMを追加することは推奨されていません。 (そしてこの勧告、またはその欠如は、多くの頭痛の種です)。参照:en.wikipedia.org/wiki/Byte_order_mark#UTF-8 - Tao
  • これは、冗長な部品表を蓄積せずにUTF-8文字列を連結できるようにするためです。その上、バイトオーダーマークは、例えばUTF-16とは異なり、UTF-8には必要ありません。 - sashoalm
  • リンクがダウンしています。 - Mateusz Piotrowski

21

やってみましたMozilla Universal Charset Detector用のC#ポート

からの例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.");
        }
    }
}    


  • Windows-1252タイプで問題なく動作しました。 - seebiscuit
  • そしてそれを使ってテキストファイルを文字列に読み込むためにどのように使うことができますか? CharsetDetectorはエンコーディングの名前を文字列形式で返します。 - Bartosz
  • @Bartoszprivate Encoding GetEncodingFromString(string encoding) { try { return Encoding.GetEncoding(encoding); } catch { return Encoding.ASCII; } } - PrivatePyle

15

コードページを検出できません

これは明らかに間違っています。どのWebブラウザにも、エンコーディングの意味がまったくないページを処理するための、何らかのユニバーサル文字セット検出機能があります。 Firefoxにはそれがあります。コードをダウンロードして、それがどのように機能するのかを確認できます。いくつかのドキュメントを見るここに。基本的に、これはヒューリスティックですが、非常にうまく機能します。

妥当な量のテキストがあれば、その言語を検出することも可能です。

これはもう一つです私はちょうどグーグルを使用して見つけました:


  • "ヒューリスティック" - ブラウザはそれを検出していないので、知識のある推測をしています。 "本当に効果的" - それでは、いつでも動かないのですか。同意したようです。 - JV.
  • HTMLの標準では、文字セットが文書で定義されていない場合は、UTF-8としてエンコードされていると見なすべきです。 - Jon Trauntvein
  • 非標準のHTMLドキュメントを読んでいない限り、これは素晴らしいことです。またはHTML以外の文書 - Kos
  • この答えは間違っているので、私は投票しなければなりませんでした。コードページを検出できないと偽っていると言っても間違っています。あなたは推測することができ、あなたの推測はかなり良いものになることができますが、"検出"できません。コードページ - z80crew
  • によると@JonTrauntveinHTML5の仕様 a character encoding declaration is required even if the encoding is US-ASCII - 宣言が欠如していると、ヒューリスティックなアルゴリズムを使用することになり、UTF8にフォールバックすることはありません。 - z80crew

8

私はこの質問には非常に遅れていることを知っています、そしてこの解決法は(英語中心の偏りと統計的/経験的テストの欠如のために)魅力的ではありません。

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

利点:

  • BOM検知内蔵
  • カスタマイズ可能なデフォルト/フォールバックエンコーディング
  • (私の経験では)UTF-8とLatin-1スタイルのファイルが混在したいくつかのエキゾチックなデータ(フランス名など)を含む西ヨーロッパベースのファイル - 基本的に米国と西ヨーロッパの環境の大部分 - はかなり信頼できます。

注:私がこのクラスを書いたのは私ですので、明らかに塩の粒でそれを取ってください! :)


7

メモ帳++この機能はそのまま使用できます。それはそれを変えることもサポートします。


7

別の解決策を探して、私はそれを見つけました

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

この解決策はちょっと重いです。

私は、最初の4バイトとおそらくxml文字セット検出に基づいた基本的なエンコーディング検出を必要としていました。

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

Java用に書かれています。

    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
    }

おそらく最初の1024バイトをファイルから読み取るだけで十分ですが、ファイル全体をロードしています。


5

誰かが93.9%の解決策を探しているなら。これは私のために働く:

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


  • とてもいい解決策です。 2つ以上のエンコーディング(UTF-8とASCI 1252)を許可する必要がある場合は、ReadAsString()の本体を許可されたエンコーディングのループで簡単にラップできます。 - ViRuSTriNiTy
  • たくさんの例を試した後、私はついにあなたのものにたどり着きました。私は今幸せなところにいます。笑ありがとう!!!!!!! - Sedrick

4

私はPythonでも似たようなことをしました。基本的には、さまざまなエンコーディングのサンプルデータが多数必要です。これらはスライド式の2バイトウィンドウで分割され、辞書(ハッシュ)に格納され、バイトペアをキーとしてエンコーディングリストの値を提供します。

その辞書(ハッシュ)を考えると、あなたはあなたの入力テキストを受け取り、そして:

  • BOM文字で始まる場合(UTF-16-BEの場合は '\ xfe \ xff'、UTF-16-LEの場合は '\ xff \ xfe'、UTF-8の場合は '\ xef \ xbb \ xbf'など)、I提案どおりに扱う
  • そうでなければ、それからテキストの十分に大きいサンプルを取り、サンプルのすべてのバイトペアを取り、そしてディクショナリから提案される最も一般的でないエンコードを選択してください。

UTFエンコードされたテキストもサンプリングした場合ではないどのBOMから始めても、2番目のステップは最初のステップからずれたものをカバーします。

これまでのところ、エラー率を減らして、私にとってはうまくいきます(サンプルデータとそれに続く入力データはさまざまな言語の字幕です)。


3

StreamReaderクラスのコンストラクターは「エンコーディングの検出」パラメーターを受け取ります。


  • 単なる「エンコーディング」です。リンクここに..そして説明は私達がエンコーディングを提供しなければならないと言っています.. - SurajS
  • @SurajS:他の過負荷を見てください。 - leppie
  • 元の作者はファイルのエンコーディングを検出したいと考えていますが、BOMマーカーは含まれていない可能性があります。 StreamReaderは、シグネチャに従ってBOMヘッダーからのエンコードを検出します。 public StreamReader(Streamストリーム、bool detectEncodingFromByteOrderMarks) - ibondre

3

ツール「uchardet」は、各文字セットの文字頻度分布モデルを使用してこれをうまく実行します。より大きなファイルとより「典型的な」ファイルは(明らかに)より信頼性があります。

Ubuntuでは、あなただけapt-get install uchardet

他のシステムでは、ソース、使用方法、入手方法を取得します。ここにドキュメント:https://github.com/BYVoid/uchardet


  • 自作によるMacの場合:brew install uchardet - Paul B

1

あなたがCライブラリにリンクすることができるならば、あなたは使うことができますlibenca。見るhttp://cihar.com/software/enca/。 manページから:

Encaは与えられたテキストファイル、または何も与えられていない場合は標準入力を読み込みます。   そして彼らの言語についての知識を使う(あなたがサポートしなければならない)   構文解析、統計分析、推測、およびブラックマジックの混合   それらのエンコーディングを決定します。

GPL v2です。


0

同じ問題が発生しましたが、それを自動的に検出するための良い解決策はまだ見つかりませんでした。 今すぐそのためにPsPad(www.pspad.com)を使用している;)正常に動作する


0

これは基本的にヒューリスティックに帰着するので、最初のヒントとして同じソースから以前に受信したファイルのエンコーディングを使用するのを助けるかもしれません。

ほとんどの人(またはアプリケーション)は、毎回同じマシン上でほぼ同じ順序で作業を行うので、Bobが.csvファイルを作成し、それをMaryに送信するときは、常にWindows-1252を使用することになります。彼のマシンのデフォルトが何であれ。

可能であれば、少しでもカスタマートレーニングを行っても何の問題もない。


0

私は実際にはファイルのエンコーディングを検出するプログラミングではなく一般的な方法を探していましたが、私はまだそれを見つけられませんでした。 さまざまなエンコーディングでテストした結果、私のテキストはUTF-7だったことがわかりました。

だから私が最初にやっていたところ: StreamReader file = File.OpenText(fullfilename);

私はそれを変更しなければなりませんでした: StreamReader file = new StreamReader(fullfilename、System.Text.Encoding.UTF7);

OpenTextはそれがUTF-8であると仮定します。

このようにStreamReaderを作成することもできます。 new StreamReader(fullfilename、true)、2番目のパラメータ。ファイルのバイトオーダーマークからエンコードを試みて検出する必要があることを意味しますが、私の場合はうまくいきませんでした。


  • いいね!誰がUTF-7でファイルを書いていますか? - John Machin
  • @ JohnMachin私はそれがまれであることに同意しますが、それは義務付けられています。 IMAPプロトコルのいくつかの部分で。それがあなたがいる場所であれば、あなたは推測する必要はないでしょう。 - tripleee

0

AkelPadでファイルを開き(または単に文字化けしたテキストをコピー/貼り付け)、[編集] - > [選択] - > [再エンコード] - > [自動検出]の順に選択します。


0

ITmezeへのアドオンとして、私はMozilla Universal Charset Detector用にC#ポートの出力を変換するためにこの関数を使用しました。

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

MSDN


0

ありがとう@エリック・アローネス言及するためのuchardet



その間、(同じ?)ツールがLinux用に存在します。chardet

あるいは、cygwinでは、あなたは使いたいかもしれません:chardetect

見る:chardetのmanページ:https://www.commandlinux.com/man-page/man1/chardetect.1.html

これは、与えられた各ファイルの文字エンコーディングをヒューリスティックに検出(推測)し、検出された各ファイルの文字エンコーディングの名前と信頼レベルを報告します。


0

これが質問されてから10年(!)が経過しましたが、それでも私はMSの優れたGPLではない解決策については言及していません。IMultiLanguage2API

すでに言及されているほとんどのライブラリはMozillaのUDEに基づいています - そしてブラウザがすでに同様の問題に取り組んでいることは合理的に思えます。私はクロムの解決策が何であるかわかりませんが、IE 5.0 MSが彼らのものをリリースして以来、それはそうです:

  1. GPLのようなライセンス問題がない
  2. おそらく永遠に支持され、維持されて
  3. 豊富な出力 - 信頼スコアと共に符号化/コードページのためのすべての有効な候補を与えます、
  4. 驚くほど使いやすい(それは単一の関数呼び出しです)。

これはネイティブのCOM呼び出しですが、これはとてもいい仕事ですCarsten Zeumerによる、それは.net使用のための相互運用混乱を処理します。他にもいくつかありますが、概してこのライブラリはそれに値する注目を集めません。


-2

ファイルを読み込むときに、UnicodeとWindowsのデフォルトのANSIコードページを検出するためにこのコードを使用します。他のコーディングでは、手動またはプログラミングによるコンテンツのチェックが必要です。これは、開いたときと同じエンコードでテキストを保存するために使用できます。 (私は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()

リンクされた質問


関連する質問

最近の質問