私たちのアプリケーションでは、さまざまなソースからテキストファイル(.txt
、.csv
など)を受け取ります。ファイルを読むときに、これらのファイルにゴミが含まれることがあります。これは、ファイルが別の未知のコードページで作成されたためです。
テキストファイルのコードページを(自動的に)検出する方法はありますか?
detectEncodingFromByteOrderMarks
コンストラクタのStreamReader
は、UTF8
およびその他のUnicodeマークの付いたファイルに対して機能しますが、私はibm850
、windows1252
のようなコードページを検出する方法を探しています。
あなたの答えをありがとう、これは私がしたことです。
私たちが受け取るファイルはエンドユーザーからのものです、彼らはコードページについての手がかりを持っていません。レシーバーもエンドユーザーであり、今ではコードページについて知っていることです。コードページは存在し、迷惑です。
Solution:
あなたはコードページを検出できません、あなたはそれを言われる必要があります。あなたはバイトを分析してそれを推測することができます、しかしそれはいくつかの奇妙な(時には面白い)結果を与えることができます。私は今それを見つけることができません、しかし私はメモ帳が中国語で英語のテキストを表示することにだまされることができると確信しています。
とにかく、これはあなたが読む必要があるものです: 絶対にすべてのソフトウェア開発者は絶対に、積極的にUnicodeと文字セットについて知っていなければなりません(言い訳はありません!) 。
具体的にジョエルは言う:
エンコーディングに関する最も重要な事実
私が今説明したことすべてを完全に忘れた場合は、非常に重要な事実を1つ覚えておいてください。どのエンコーディングを使用しているのかを知らずに文字列を取得しても意味がありません。あなたはもはやあなたの頭を砂の中に突き刺すことはできず、そして「普通の」テキストはASCIIであるというふりをすることはできません。プレーンテキストのようなものはありません。
文字列、メモリ内、ファイル内、または電子メールメッセージ内に文字列がある場合は、それがどのエンコーディングであるのかを知っておく必要があります。そうしないと、解釈できないか、正しく表示できません。
あなたが非UTFエンコーディング(すなわちBOMがない)を検出しようとしているなら、あなたは基本的にテキストの発見的方法と統計的分析に行きます。 Mozillaのユニバーサル文字セット検出に関する論文 ( 同じリンク、Wayback Machineによるフォーマットの改善 )をご覧になるとよいでしょう。
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.");
}
}
}
私はこの質問には非常に遅れていることを知っていますし、この解決法は英語中心の偏りと統計的/経験的テストの欠如のために一部の人にとって魅力的ではありません。
http://www.architectshack.com/TextFileEncodingDetector.ashx
利点:
注:私がこのクラスを書いたのは私ですので、明らかに塩の粒でそれを取ってください! :)
別の解決策を探して、私はそれを見つけた
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バイトをファイルから読み取るだけで十分ですが、ファイル全体をロードしています。
Notepad ++ この機能はそのまま使えます。それはそれを変更することもサポートします。
誰かが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();
}
}
}
私はPythonでも似たようなことをしました。基本的には、さまざまなエンコーディングからの多数のサンプルデータが必要です。これらはスライド式の2バイトウィンドウで細分化され、辞書(ハッシュ)に格納され、エンコーディングリストの値を提供するバイトペアをキーとします。
その辞書(ハッシュ)を考えると、あなたはあなたの入力テキストを取り、そして:
BOMで始まらないしないUTFエンコードされたテキストもサンプリングした場合、2番目のステップは最初のステップから抜けたテキストをカバーします。
これまでのところ、それは私のために働きます(サンプルデータとそれに続く入力データはさまざまな言語の字幕です)。
ツール「uchardet」は、各文字セットの文字頻度分布モデルを使用してこれをうまく実行します。より大きなファイルとより「典型的な」ファイルは、(明らかに)より信頼性があります。
Ubuntuでは、あなただけのapt-get install uchardet
。
他のシステムでは、ソース、使用方法、およびドキュメントをここで入手してください。 https://github.com/BYVoid/uchardet
StreamReaderクラスのコンストラクターは「エンコーディングの検出」パラメーターを受け取ります。
Cライブラリにリンクできる場合は、libenca
を使用できます。 http://cihar.com/software/enca/ を参照してください。 manページから:
Encaは与えられたテキストファイル、または何も与えられていない場合は標準入力を読み、それらの言語に関する知識(あなたがサポートしていなければなりません)と解析、統計分析、推測、そしてブラックマジックを組み合わせてエンコーディングを決定します。
GPL v2です。
同じ問題が発生しましたが、それを自動的に検出するための良い解決策はまだ見つかりませんでした。今すぐそのためにPsPad(www.pspad.com)を使用しています;)正常に動作します
uchardet
に言及してくれてありがとう@ Erik Aronesty 。
一方、Linux用の(同じ?)ツールが存在します:chardet
。
または、cygwinではchardetect
を使用することをお勧めします。
参照してください: chardetのmanページ:https://www.commandlinux.com/man-page/man1/chardetect.1.html
これにより、各ファイルの文字エンコーディングがヒューリスティックに検出(推測)され、検出された各ファイルの文字エンコーディングの名前と信頼レベルが報告されます。
私は実際にはファイルのエンコーディングを検出するプログラミングではなく一般的な方法を探していましたが、私はまだそれを見つけられませんでした。さまざまなエンコーディングでテストした結果、私のテキストはUTF-7だったことがわかりました。
だから私が最初にやっていたところ:StreamReader file = File.OpenText(fullfilename);
私はそれを変更する必要がありました:StreamReader file = new StreamReader(fullfilename、System.Text.Encoding.UTF7);
OpenTextはUTF-8と見なします。
この新しいStreamReader(fullfilename、true)のようにStreamReaderを作成することもできます。これは、ファイルのバイトオーダーマークからエンコードを試みて検出する必要があることを意味しますが、私の場合はうまくいきません。
ITmezeへのアドオンとして、私はMozilla Universal Charset Detector用にC#ポートの出力を変換するためにこの関数を使用しました。
private Encoding GetEncodingFromString(string codePageName)
{
try
{
return Encoding.GetEncoding(codePageName);
}
catch
{
return Encoding.ASCII;
}
}
AkelPadでファイルを開き(または単に文字化けしたテキストをコピー/貼り付け)、[編集] - > [選択] - > [再エンコード] - > [自動検出]の順に選択します。
これは基本的にヒューリスティックに帰着するので、最初のヒントとして同じソースから以前に受信したファイルのエンコーディングを使用するのを助けるかもしれません。
ほとんどの人(またはアプリケーション)は、毎回同じマシン上でほぼ同じ順序で作業を行うので、Bobが.csvファイルを作成し、それをMaryに送信するときは、常にWindows-1252を使用することになります。彼のマシンのデフォルトが何であれ。
可能であれば、少しでもカスタマートレーニングを行っても何の問題もありません:-)
これが求められてから10Y(!)が経過しましたが、それでも私はMSの優れたGPLではない解決策については言及していません。 IMultiLanguage2 API。
すでに言及されているほとんどのライブラリはMozillaのUDEに基づいています - そしてブラウザがすでに同様の問題に取り組んでいることは合理的に思えます。私はクロムの解決策が何であるかわかりませんが、IE 5.0 MSが彼らのものをリリースしたので、そしてそれはそうです:
これはネイティブのCOM呼び出しですが、 Carsten Zeumerによる非常に素晴らしい作業 があります。これは、.net使用のための相互運用混乱を処理します。他にもいくつかありますが、概してこのライブラリはそれに値する注目を集めません。