web-dev-qa-db-ja.com

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

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

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

detectEncodingFromByteOrderMarksコンストラクタのStreamReaderは、UTF8およびその他のUnicodeマークの付いたファイルに対して機能しますが、私はibm850windows1252のようなコードページを検出する方法を探しています。


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

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

Solution:

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

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

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

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

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

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

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

256
JV.

あなたが非UTFエンコーディング(すなわちBOMがない)を検出しようとしているなら、あなたは基本的にテキストの発見的方法と統計的分析に行きます。 Mozillaのユニバーサル文字セット検出に関する論文同じリンク、Wayback Machineによるフォーマットの改善 )をご覧になるとよいでしょう。

31
Tomer Gabel

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

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

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

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

これも別の例です 私はGoogleを使ったところです。

15
shoosh

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

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

利点:

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

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

8
Tao

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

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
TarmoPikaro

Notepad ++ この機能はそのまま使えます。それはそれを変更することもサポートします。

7
hegearon

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

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

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

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

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

これまでのところ、それは私のために働きます(サンプルデータとそれに続く入力データはさまざまな言語の字幕です)。

4
tzot

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

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

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

3
Erik Aronesty

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

3
leppie

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

Encaは与えられたテキストファイル、または何も与えられていない場合は標準入力を読み、それらの言語に関する知識(あなたがサポートしていなければなりません)と解析、統計分析、推測、そしてブラックマジックを組み合わせてエンコーディングを決定します。

GPL v2です。

1
Kundor

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

0
DeeCee

uchardetに言及してくれてありがとう@ Erik Aronesty

一方、Linux用の(同じ?)ツールが存在します:chardet
または、cygwinではchardetectを使用することをお勧めします。

参照してください: chardetのmanページ:https://www.commandlinux.com/man-page/man1/chardetect.1.html

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

0
Schlacki

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

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

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

OpenTextはUTF-8と見なします。

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

0
Intraday Tips

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

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

MSDN

0
PrivatePyle

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

0
plavozont

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

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

可能であれば、少しでもカスタマートレーニングを行っても何の問題もありません:-)

0
devstuff

これが求められてから10Y(!)が経過しましたが、それでも私はMSの優れたGPLではない解決策については言及していません。 IMultiLanguage2 API。

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

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

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

0
Ofek Shilon