テキストファイルのエンコード/コードページを検出する方法


295

私たちのアプリケーションでは、テキストファイル(受信.txt.csv多様なソースから、など)。読み取り時、これらのファイルは別の/不明なコードページで作成されているため、ゴミが含まれる場合があります。

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

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


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

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

解決:

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

回答:


260

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

とにかく、これはあなたが読む必要があるものです: 絶対最小値すべてのソフトウェア開発者絶対に、積極的にUnicodeと文字セットについて知っておく必要があります(言い訳なし!)

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

エンコーディングに関する最も重要な事実

今説明したすべてのことを完全に忘れてしまった場合は、1つの非常に重要な事実を思い出してください。使用するエンコーディングがわからない文字列を使用しても意味がありません。砂に頭をくっつけて、「プレーン」テキストがASCIIであるふりをすることはできません。平文ほどのものはありません。

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


43
私は2つの理由でこの回答に反対しました。まず、「あなたは言われる必要がある」と言っても役に立たない。誰が教えてくれますか。また、どのような手段で伝えますか。ファイルを保存したのが私なら、誰に尋ねればよいですか?私自身?第二に、この記事は質問に回答するためのリソースとしては特に役立ちません。この記事は、David Sedarisスタイルで記述されたエンコーディングの歴史の詳細です。私は物語に感謝しますが、それは単純に/直接質問に答えるものではありません。
geneorama 2013

9
@geneorama、私はJoelの記事があなたの質問にこれまで以上にうまく対処していると思いますが、ここに行きます...メディアは確かにテキストが受信される環境に依存します。ファイル(または何でも)にその情報が含まれているほうがよい(HTMLとXMLを考えている)それ以外の場合は、テキストを送信する人がその情報を提供できるようにする必要があります。あなたがファイルを作成したのがあなたなら、それがどのエンコーディングを使用しているのか分からないのですか?
JV。

4
@geneorama、続き...最後に、記事が質問に答えない主な理由は、その質問に対する単純な答えがないためだと思います。質問が「どうやって推測するのか...」だったとしたら、私は違う答えを出したでしょう。
JV。

1
@JV私は後で、xml / htmlが文字エンコーディングを指定できることを学びました。その便利なヒントに言及してくれてありがとう。
geneorama 2013

1
@JV "ファイルを作成する"は、言葉の選択としては不適切かもしれません。ユーザーが生成するファイルのエンコーディングをユーザーが指定できると思います。最近、Hiveを使用してHadoopクラスターからファイルを「作成」し、さまざまなクライアントマシンにダウンロードする前にFTPに渡しました。結果にはUnicodeのゴミが含まれていましたが、どのステップで問題が発生したのかはわかりません。エンコーディングを明示的に指定したことはありません。各ステップでエンコーディングを確認できるといいのですが。
geneorama 2013

31

非UTFエンコーディング(つまりBOMなし)を検出する場合、基本的にはテキストのヒューリスティックスと統計分析を使用します。ユニバーサル文字セット検出に関するMozillaペーパー同じリンク、Wayback Machineによるより優れたフォーマット)をご覧になることをお勧めします。


9
おかしなことに、Firefox 3.05のインストールではそのページがUTF-8として検出され、多数の疑問符(a-diamond)のグリフが表示されますが、ソースにはWindows-1252のメタタグがあります。文字エンコーディングを手動で変更すると、ドキュメントが正しく表示されます。
devstuff 2008

5
「UTF以外のエンコーディング(つまりBOMなし)を検出しようとしている場合」という文は、少し誤解を招く可能性があります。ユニコード規格では、BOMをutf-8ドキュメントに追加することを推奨していません。(そして、この推奨、またはその欠如は、多くの頭痛の種です)。ref:en.wikipedia.org/wiki/Byte_order_mark#UTF-8
Tao

これは、冗長なBOMを蓄積することなくUTF-8文字列を連結できるようにするためです。さらに、UTF-16とは異なり、UTF-8ではバイト順マークは必要ありません。
sashoalm 2013

26

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

1
Windows-1252タイプで問題なく動作しました。
ビスケット2014

そして、それを使用してテキストファイルを文字列に読み取るにはどうすればよいでしょうか。CharsetDetectorはエンコードの名前を文字列形式で返し、それだけです...
Bartosz

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

15

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

これは明らかに誤りです。すべてのWebブラウザーには、エンコードについて何の表示もないページを処理するための、ある種の汎用文字セット検出機能があります。Firefoxには1つあります。コードをダウンロードして、それがどのように機能するかを確認できます。こちらのドキュメントをご覧ください。基本的に、これはヒューリスティックですが、本当にうまくいくものです。

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

これが、Googleを使用して見つけた別の例です。


39
「ヒューリスティック」-ブラウザーはそれを完全に検出していないため、知識に基づいた推測を行っています。「本当にうまくいく」-それでそれはいつもうまくいかないのですか?私たちが同意しているように聞こえます。
JV。

10
HTMLの標準では、文字セットがドキュメントで定義されていない場合、UTF-8としてエンコードされていると見なす必要があると規定されています。
Jon Trauntvein

5
非標準のHTMLドキュメントを読んでいない限り、これはすばらしいことです。または非HTMLドキュメント。
コス

2
この答えは間違っているので、反対票を投じなければなりませんでした。コードページを検出できないのは誤りだと言うのは間違いです。あなたは推測することができ、推測はかなり良いかもしれませんが、コードページを「検出」することはできません。
z80crew 2017

1
@JonTrauntvein HTML5仕様に よれば、a character encoding declaration is required even if the encoding is US-ASCII宣言がないと、UTF8にフォールバックするのではなく、ヒューリスティックアルゴリズムが使用されます。
z80crew 2017

9

私はこの質問に非常に遅れていることを知っていますが、この解決策は一部には魅力的ではありません(英語中心のバイアスと統計的/経験的テストの欠如のため)が、特にアップロードされたCSVデータの処理に関しては非常にうまく機能します:

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

利点:

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

注:このクラスを作成したのは私なので、明らかに塩分を1つ入れてください。:)



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バイトを読み取るには十分ですが、ファイル全体をロードしています。


7

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

とても良い解決策です。3つ以上のエンコーディング(UTF-8およびASCI 1252)を許可する必要がある場合、許可されたエンコーディングのループでReadAsString()の本体を簡単にラップできます。
ViRuSTriNiTy

たくさんの例を試した後、ようやくあなたの例に行きました。私は今幸せな場所にいます。笑ありがとう!!!!!!!
Sedrick 2017

これは1252と1250を検出する方法に対する答えではないかもしれませんが、BOMの有無にかかわらず、「UTF-8を検出する方法」の答えになるはずです。
チャック

4

Pythonでも同様のことを行いました。基本的に、さまざまなエンコーディングからのサンプルデータがたくさん必要です。これらは、スライドする2バイトウィンドウで分解され、エンコーディングのリストの値を提供するバイトペアをキーとして辞書(ハッシュ)に保存されます。

その辞書(ハッシュ)を考えると、入力テキストを受け取り、次のことを行います。

  • 任意のBOM文字(UTF-16-BEの場合は「\ xfe \ xff」、UTF-16-LEの場合は「\ xff \ xfe」、UTF-8の場合は「\ xef \ xbb \ xbf」)で始まる場合、I提案されたようにそれを扱います
  • そうでない場合は、テキストの十分な大きさのサンプルを取り、サンプルのすべてのバイトペアを取り、辞書から推奨される最も一般的ではないエンコーディングを選択します。

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

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


4

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

ubuntuでは、あなただけapt-get install uchardetです。

他のシステムでは、https//github.com/BYVoid/uchardetでソース、使用法、ドキュメントを入手してください。


Macでは、自作を介して:brew install uchardet
Paul B

3

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


それはちょうど、「エンコード」だリンク ..ここ..と記述は、当社がエンコーディングを提供しなければならないと言う
SurajS

@SurajS:他のオーバーロードを見てください。
leppie 2015年

元の作成者は、BOMマーカーがない可能性のあるファイルのエンコーディングを検出したいと考えています。StreamReaderは、署名に従ってBOMヘッダーからのエンコーディングを検出します。public StreamReader(ストリームストリーム、bool detectEncodingFromByteOrderMarks)
ibondre 2015

1

Cライブラリにリンクできる場合は、を使用できますlibencahttp://cihar.com/software/enca/を参照してください。manページから:

Encaは、指定されたテキストファイル、または何も指定されていない場合は標準入力を読み取り、その言語に関する知識(ユーザーがサポートする必要があります)と、解析、統計分析、推測、および黒魔術を組み合わせてエンコードを決定します。

GPL v2です。


0

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


0

それは基本的にヒューリスティックスに帰着するので、同じソースから以前に受信したファイルのエンコーディングを最初のヒントとして使用すると役立つ場合があります。

ほとんどの人(またはアプリケーション)は毎回ほぼ同じ順序で、多くの場合は同じマシンで作業を行うため、ボブが.csvファイルを作成してメアリーに送信すると、常にWindows-1252または彼のマシンのデフォルトは何でも。

可能であれば、少しの顧客トレーニングでもどちらにも害はありません:-)


0

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

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

私はそれを次のように変更する必要がありました:StreamReader file = new StreamReader(fullfilename、System.Text.Encoding.UTF7);

OpenTextは、UTF-8を想定しています。

この新しいStreamReader(fullfilename、true)のようなStreamReaderを作成することもできます。2番目のパラメーターは、ファイルのバイトオーダーマークからエンコーディングを検出および検出する必要があることを意味しますが、私の場合は機能しませんでした。


@JohnMachinそれはまれであることに同意しますが、IMAPプロトコルの一部などでは必須です。それがあなたのいるところなら、あなたは推測する必要はないでしょう。
Tripleee、2016年

0

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


0

ITmeze投稿のアドオンとして、この関数を使用してC#ポートの出力をMozilla Universal Charset Detectorに変換しました

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

MSDN


0

言及してくれてありがとう@ Erik Aronestyuchardet

一方、Linuxには(同じ?)ツールがありますchardet
または、cygwinで使用することもできます。chardetect

参照:chardet manページ:https : //www.commandlinux.com/man-page/man1/chardetect.1.html

これにより、特定の各ファイルの文字エンコーディングを発見的に検出(推測)し、検出された各ファイルの文字エンコーディングの名前と信頼レベルを報告します。


-1

このコードを使用して、ファイルを読み取るときに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()

-1

これが要求されてから10年(!)が経過しましたが、MSのGPLに準拠していない優れたソリューションであるIMul​​tiLanguage2 API についての言及はまだありません。

すでに述べたほとんどのライブラリーはMozillaのUDEに基づいています-そして、ブラウザーがすでに同様の問題に取り組んできたのは理にかなっているようです。Chromeのソリューションが何かはわかりませんが、IE 5.0 MSからリリースされました。

  1. GPLなどのライセンスの問題はありません。
  2. おそらく永遠に支えられ維持され、
  3. 豊富な出力を提供-信頼スコアとともに、エンコーディング/コードページのすべての有効な候補、
  4. 驚くほど使いやすい(単一の関数呼び出しです)。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.