Webページの取得を例に、MITライセンス準拠のドネーションウェア「ReadJEnc」を使用して、文字エンコーディングを推定する方法を解説する。
対象:.NET 2.0以降(Webページを取得する部分は.NET 4.5以降)
任意のWebページの内容を取得するには、現状では文字コードの推定が必要になる。「.NET TIPS:HttpClientクラスでシフトJISのWebページを取得するには?[C#、VB]」では、W3Cの推奨方式に準じて実装してみた。それでも文字化けしてしまうWebサイトでは、どうしたらよいだろうか? それには、Webページの内容を単にbyteの並びとして取得し、そのbyte列のパターンから文字エンコーディングを推定することになるだろう。本稿では、文字エンコーディングを推定して文字列に変換してくれるオープンソースのライブラリ「ReadJEnc」の使い方を解説する。
バイト列のパターンから文字エンコーディングを確実に判定できるアルゴリズムは存在しない。そこで、文字コードの「自動判別」とよくいわれるが、本稿では「推定」という言葉を使うことにする。そのような文字エンコーディングを推定するライブラリはいくつも公開されている。例えば次のようなものがある。
これらはInternet ExplorerやFirefoxで使われているもので推定精度は高そうではあるが、C#/VBから利用するにはハードルも高い。手軽に.NET Frameworkから直接参照できる形式のライブラリはないものか。その一つに、hnx8氏によって2014年に公開された「ReadJEnc」がある。ReadJEncはMITライセンス準拠のドネーションウェアとなっている。本稿では、Webページをbyte配列として取得し、それをReadJEncで文字列に変換する方法を紹介する。
ダウンロードページから入手したzipファイルの中身を適当なフォルダーに展開しておく。その中の「Hnx8.ReadJEnc.dll」ファイルをプロジェクトの参照設定に追加すれば、準備は完了だ(次の画像)。
なお、「Hnx8.ReadJEnc.dll」ファイルと同じフォルダーに「Hnx8.ReadJEnc.xml」ファイルがあれば(zipファイルをそのまま展開したら存在するはずだ)、Visual StudioのIntelliSenseが機能する(次の画像)。
HttpClientクラス(System.Net.Http名前空間)を利用するなら、GetByteArrayAsyncメソッドを使えばよい。
「.NET TIPS:HttpClientクラスでWebページを取得するには?[C#、VB]」で作成したGetWebPageAsyncメソッドをベースにして書き換えると、次のコードのようになる。
static async Task<byte[]> GetWebPageAsync(Uri uri)
// メソッドが返す型はTask<string>からTask<byte[]>に変更する
{
// HttpClientオブジェクトを作って使用する
using (var client = new HttpClient())
{
……省略……
try
{
//// Webページの内容を文字列として取得する
//return await client.GetStringAsync(uri);
// Webページの内容をbyte配列として取得する
return await client.GetByteArrayAsync(uri);
}
catch (HttpRequestException e)
{
……省略……
}
return null;
}
}
Async Function GetWebPageAsync(uri As Uri) As Task(Of Byte())
' メソッドが返す型はTask Task(Of String)からTask(Of Byte())に変更する
' HttpClientオブジェクトを作って使用する
Using client = New HttpClient()
……省略……
Try
'' Webページの内容を文字列として取得する
'Return Await client. GetStringAsync (uri)
' Webページの内容をbyte配列として取得する
Return Await client.GetByteArrayAsync(uri)
Catch e As HttpRequestException
……省略……
End Try
Return Nothing
End Using
End Function
上のメソッドで取得できたbyte配列を、ReadJEncクラスのインスタンスのGetEncodingメソッドに渡せばよい。ReadJEncクラスが文字エンコーディングを推定して文字列に変換した結果が得られる。また、このメソッドの返値は、推定できた文字エンコーディングとなっている(次のコード)。
……省略……
static void Main(string[] args)
{
……省略……
// 取得したいWebページのURI
Uri webUri = new Uri(……省略……);
// GetWebPageAsyncメソッドを呼び出す
//Task<string> webTask = GetWebPageAsync(webUri);
Task<byte[]> webTask = GetWebPageAsync(webUri);
webTask.Wait(); // Mainメソッドではawaitできないので、処理が完了するまで待機する
//string result = webTask.Result; // 結果を取得
byte[] byteData = webTask.Result; // 結果を取得
string result = null; // デコード結果が格納されるstring変数
if (byteData != null)
{
// byte配列として取得できたので、ReadJEncのJPインスタンスを使ってデコードする
Hnx8.ReadJEnc.CharCode charCode
= Hnx8.ReadJEnc.ReadJEnc.JP.GetEncoding(byteData, byteData.Length, out result);
Console.WriteLine("文字エンコーディング推定結果: {0}", charCode.ToString());
}
……省略(経過時間と得られた文字列を表示)……
}
Sub Main()
……省略……
' 取得したいWebページのURI
Dim webUri As Uri = New Uri(……省略……)
' GetWebPageAsyncメソッドを呼び出す
'Dim webTask As Task(Of String) = GetWebPageAsync(webUri)
Dim webTask As Task(Of Byte()) = GetWebPageAsync(webUri)
webTask.Wait() ' Mainメソッドではawaitできないので、処理が完了するまで待機する
'Dim result As String = webTask.Result ' 結果を取得
Dim byteData As Byte() = webTask.Result ' 結果を取得
Dim result As String = Nothing ' デコード結果が格納されるstring変数
If (byteData IsNot Nothing) Then
' byte配列として取得できたので、ReadJEncのJPインスタンスを使ってデコードする
Dim charCode As Hnx8.ReadJEnc.CharCode _
= Hnx8.ReadJEnc.ReadJEnc.JP.GetEncoding(byteData, byteData.Length, result)
Console.WriteLine("文字エンコーディング推定結果: {0}", charCode.ToString())
End If
……省略(経過時間と得られた文字列を表示)……
End Sub
このサンプルコードで、WebページのURL(ローカル変数「webUri」を作るときに与える文字列、コード内では省略している)を変えて試した結果を以下に示す。
日本語のサイト、あるいは他言語であってもUTF-8のサイトでは、きちんとデコードできた(次の画像)。
ReadJEncクラスの「JP」インスタンスでは、UTF-8ではない他言語のサイトは正しく推定できない(次の画像)。これは、言語ごとにインスタンスが分かれていることから想像できる結果である(画像にも載せたが、「CN」インスタンスを使えば中国語簡体字のエンコーディングを推定できる)。
上述した注意点があることをわきまえて使えば、ReadJEncクラスはとても便利なライブラリである。その他、ReadJEncクラスの詳細は作者のブログ記事をご覧いただきたい。また、ダウンロードできるパッケージにはC#のソースコードも同梱されている。
利用可能バージョン:.NET Framework 2.0以降
カテゴリ:クラスライブラリ 処理対象:文字列 処理対象:ネットワーク
使用ライブラリ:HttpClientクラス(System.Net.Http名前空間)
使用ライブラリ:ReadJEncクラス(Hnx8.ReadJEnc名前空間)
関連TIPS:HttpClientクラスでWebページを取得するには?[C#、VB]
関連TIPS:HttpClientクラスでシフトJISのWebページを取得するには?[C#、VB]
関連TIPS:WebClientクラスでWebページを取得するには?
Copyright© Digital Advantage Corp. All Rights Reserved.