web-dev-qa-db-ja.com

テキストファイルの文字エンコードを検出する方法は?

ファイルで使用されている文字エンコードを検出しようとしています。

私はこのコードを使って標準エンコーディングを取得しようとします

public static Encoding GetFileEncoding(string srcFile)
    {
      // *** Use Default of Encoding.Default (Ansi CodePage)
      Encoding enc = Encoding.Default;

      // *** Detect byte order mark if any - otherwise assume default
      byte[] buffer = new byte[5];
      FileStream file = new FileStream(srcFile, FileMode.Open);
      file.Read(buffer, 0, 5);
      file.Close();

      if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
        enc = Encoding.UTF8;
      else if (buffer[0] == 0xfe && buffer[1] == 0xff)
        enc = Encoding.Unicode;
      else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
        enc = Encoding.UTF32;
      else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
        enc = Encoding.UTF7;
      else if (buffer[0] == 0xFE && buffer[1] == 0xFF)      
        // 1201 unicodeFFFE Unicode (Big-Endian)
        enc = Encoding.GetEncoding(1201);      
      else if (buffer[0] == 0xFF && buffer[1] == 0xFE)      
        // 1200 utf-16 Unicode
        enc = Encoding.GetEncoding(1200);


      return enc;
    }

最初の5バイトは60、118、56、46、49です。

これらの最初の5バイトに一致するエンコーディングを示すグラフはありますか?

72
Cédric Boivin

BOMを持つファイルに依存することはできません。 UTF-8では必要ありません。また、非UnicodeエンコードにはBOMもありません。ただし、エンコードを検出する方法は他にもあります。

UTF-32

BOMは00 00 FE FF(BEの場合)またはFF FE 00 00(LEの場合)です。

ただし、UTF-32はBOMがなくても簡単に検出できます。これは、Unicodeコードポイントの範囲がU + 10FFFFに制限されているため、UTF-32ユニットには常にパターン00 {00-10} xx xx(BEの場合)またはxx xx {00-10} 00(LEの場合)があるためです。 。データの長さが4の倍数であり、これらのパターンのいずれかに従っている場合、UTF-32であると想定できます。バイト指向エンコーディングでは00バイトがまれであるため、誤検知はほとんど不可能です。

US-ASCII

BOMはありませんが、必要ありません。 ASCIIは、80-FFの範囲にバイトがないことで簡単に識別できます。

UTF-8

BOMはEF BB BFです。しかし、これに頼ることはできません。特にWindows以外のシステムで作成された場合、UTF-8ファイルの多くにはBOMがありません。

ただし、ファイルがUTF-8として検証される場合、isUTF-8であると安全に想定できます。誤検知はまれです。

具体的には、データがASCIIではない場合、2バイトシーケンスの誤検知率は3.9%(1920/49152)のみです。 7バイトシーケンスの場合、1%未満です。 12バイトシーケンスの場合、0.1%未満です。 24バイトシーケンスの場合、100万分の1未満です。

UTF-16

BOMはFE FF(BEの場合)またはFF FE(LEの場合)です。 UTF-16LE BOMはUTF-32LE BOMの先頭にあるため、最初にUTF-32を確認してください。

主にISO-8859-1文字で構成されるファイルがある場合、ファイルのバイトの半分が00であることもUTF-16の強力な指標になります。

それ以外の場合、BOMなしでUTF-16を認識する唯一の信頼できる方法は、サロゲートペア(D [8-B] xx D [CF] xx)を探すことですが、非BMP文字はあまり使用されないため、このアプローチは実用的ではありません。

XML

ファイルが3C 3F 78 6D 6Cのバイト(ASCII文字 "<?xml")で始まる場合、encoding=宣言。存在する場合は、そのエンコーディングを使用します。存在しない場合は、デフォルトのXMLエンコーディングであるUTF-8を想定します。

EBCDICをサポートする必要がある場合は、同等のシーケンス4C 6F A7 94 93も探します。

一般に、エンコーディング宣言を含むファイル形式がある場合は、エンコーディングを推測しようとするのではなく、その宣言を探します。

上記のどれでもない

他にも数百のエンコーディングがあり、検出にはより多くの労力が必要です。 Mozillaの文字セット検出器 または その.NETポート を試すことをお勧めします。

妥当なデフォルト

UTFエンコーディングを除外し、異なるエンコーディングを指すエンコーディング宣言または統計的検出がない場合は、 ISO-8859-1 または密接に関連する Windows -1252 。 (最新のHTML標準では、Windows-1252として解釈される「ISO-8859-1」宣言が必要です。)Windowsのデフォルトコードページであること英語(およびスペイン語、ポルトガル語、ドイツ語、フランス語などのその他の一般的な言語)の場合、UTF-8以外の最も一般的なエンコーディングです。

79
dan04

「単純な」ソリューションを追求したい場合は、私がまとめたこのクラスが役に立つかもしれません。

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

最初にBOM検出を自動的に行い、次にBOMなしのUnicodeエンコーディングと他のデフォルトエンコーディング(一般的にWindows-1252、.NetでEncoding.ASCIIと誤ってラベル付けされている)を区別しようとします。

上記のように、NCharDetまたはMLangを含む「より重い」ソリューションの方が適切な場合があります。このクラスの概要ページで説明しているように、可能な限りユーザーと何らかのインタラクティブ機能を提供するのが最善です。 100%の検出率は不可能です!

9
Tao

StreamReaderを使用して、エンコードを検出するように指示します。

using (var reader = new System.IO.StreamReader(path, true))
{
    var currentEncoding = reader.CurrentEncoding;
}

そしてCode Page Identifiershttps://msdn.Microsoft.com/en-us/library/windows/desktop/dd317756(v = vs.85).aspx それに応じてロジックを切り替えるため。

5
Phil Hunt

いくつかの答えがここにありますが、誰も有用なコードを投稿していません。

StreamReaderクラスのFramework 4でMicrosoftが検出するすべてのエンコーディングを検出するコードを次に示します。

BOMはストリームの最初のバイトであるため、ストリームから何かを読み取る前に、ストリームを開いた直後にこの関数を呼び出す必要があることは明らかです。

この関数には、シーク可能なStream(たとえば、FileStream)が必要です。シークできないストリームがある場合は、すでに読み取られているがBOMではないバイトを含むバイトバッファーを返す、より複雑なコードを記述する必要があります。

/// <summary>
/// UTF8    : EF BB BF
/// UTF16 BE: FE FF
/// UTF16 LE: FF FE
/// UTF32 BE: 00 00 FE FF
/// UTF32 LE: FF FE 00 00
/// </summary>
public static Encoding DetectEncoding(Stream i_Stream)
{
    if (!i_Stream.CanSeek || !i_Stream.CanRead)
        throw new Exception("DetectEncoding() requires a seekable and readable Stream");

    // Try to read 4 bytes. If the stream is shorter, less bytes will be read.
    Byte[] u8_Buf = new Byte[4];
    int s32_Count = i_Stream.Read(u8_Buf, 0, 4);
    if (s32_Count >= 2)
    {
        if (u8_Buf[0] == 0xFE && u8_Buf[1] == 0xFF)
        {
            i_Stream.Position = 2;
            return new UnicodeEncoding(true, true);
        }

        if (u8_Buf[0] == 0xFF && u8_Buf[1] == 0xFE)
        {
            if (s32_Count >= 4 && u8_Buf[2] == 0 && u8_Buf[3] == 0)
            {
                i_Stream.Position = 4;
                return new UTF32Encoding(false, true);
            }
            else
            {
                i_Stream.Position = 2;
                return new UnicodeEncoding(false, true);
            }
        }

        if (s32_Count >= 3 && u8_Buf[0] == 0xEF && u8_Buf[1] == 0xBB && u8_Buf[2] == 0xBF)
        {
            i_Stream.Position = 3;
            return Encoding.UTF8;
        }

        if (s32_Count >= 4 && u8_Buf[0] == 0 && u8_Buf[1] == 0 && u8_Buf[2] == 0xFE && u8_Buf[3] == 0xFF)
        {
            i_Stream.Position = 4;
            return new UTF32Encoding(true, true);
        }
    }

    i_Stream.Position = 0;
    return Encoding.Default;
}
4
Elmue
2
Jon
2
Steven K.

de を使用します。これは、Mozilla Universal Charset DetectorのC#ポートです。使いやすく、いくつかの本当に良い結果が得られます。

1
Julien Jacobs

ファイルがバイト60、118、56、46、49で始まる場合、あいまいなケースがあります。 UTF-8(BOMなし)またはASCII、ANSI、ISO-8859-1などのシングルバイトエンコーディングのいずれかです。

1
Codo