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