2015年12月8日火曜日

日本語エンコーディングはややこしい

今日の目標→

日本語のEncodingについてあらためて調べているところである。とりあえず途中経過の報告を。

●各種エンコードのHTMLをブラウザで表示するテスト

まずは基本的なところで、いろいろなエンコードのHTMLファイルをWebブラウザで表示してみた。ファイルは公開スペースに置いたので、よかったらご自由にアクセスしてください。

こちら→ http://pilikala.net/yuima/encoding/

この9種類のHTMLファイルを、FireFoxとIEで表示した結果が次である。

No.ファイル名エンコードcharset備考FFIE
1.file_Shift_JIS.htmlCP932Shift_JIS-
2.file_EUC-JP.htmlCP51932EUC-JP-
3.file_ISO-2022-JP.htmlCP50221ISO-2022-JP-
4.file_UTF-8.htmlUTF-8UTF-8-
5.file_UTF-8_BOM.htmlUTF-8UTF-8BOMを付加
6.file_UTF-16LE.htmlUTF-16LEUTF-16LE-
7.file_UTF-16LE_BOM.htmlUTF-16LEUTF-16BOMを付加
8.file_UTF-16BE.htmlUTF-16BEUTF-16BE-
9.file_UTF-16BE_BOM.htmlUTF-16BEUTF-16BOMを付加×

なぜかIEがひとつ表示に失敗している。HTTPヘッダでcharsetも送信しているはずなのにおかしいな。

てな感じで調査継続中、続きは、この記事に追加していきます。

2015年12月7日月曜日

P013-URLをドラッグ&ドロップ

今日の目標→

UnicodeのBOMについて探求する前にちょっと脇道へ。 いちいちURLを入力するのが面倒になってきたので、 今回はWebブラウザからURLをドラッグ&ドロップできるようにプログラムを改造してみる。

●Webブラウザからのドラッグデータを受け取るには

最近のWebブラウザは、 画面上のリンクや画像などをドラッグ&ドロップで持ち出せるので非常に便利である。 問題は、Webブラウザのドラッグ&ドロップには標準的な手法が決まっておらず、 各陣営が好き勝手にやっているという点だ。

試しにフォームのDragDropイベントに次のようなコードを書いて実行してみるといい。

ブラウザ画面から上記のフォームにリンクか何かをドラッグ&ドロップすると、 いろいろな形式のデータが取得可能なことがわかる。 ただし種類はFireFoxとChromeとMS Edgeでバラバラだ。 唯一共通しているのは、

UniformResourceLocator

という形式のドロップデータである。 これは字面からわかる通りURLを表している。 この形式のドロップデータからURLを文字列として取り出すには次のように書く。

URL以外のデータにも便利なものがありそうで、 たとえばブラウザから画像をドラッグ&ドロップした場合、 ローカルPCのキャッシュデータなんかもとれるみたいだが、 ブラウザごとに挙動が変わるのが困るなあ。 まあURLさえわかってれば、もっかいデータを読みにいけばいいんだし…。

●プロジェクトの作成

というわけで、前々回(P011~)で作成したNetJob2を改造する。

  1. プロジェクト作成ウィンドウを開く
  2. 「Windowsフォームアプリケーション」テンプレート、名前は「NetJob3」でプロジェクトを作る
  3. Form1.csを開き、NetJob2のFomr1.csをコピペし、次のように改造する

プログラムを実行し、ブラウザからURLをドラッグ&ドロップできることを確認する。やっぱドラッグ&ドロップは便利だなあ。

2015年12月6日日曜日

P012-BOMの処理はどうするか

今日の目標→

前回のプログラムで、Unicodeのファイルを読み込むと、ときどき先頭に妙な空白が表示されるのに気がついた。これはBOMだ。何とかしないと。

●BOM(バイトオーダーマーク)について

Unicodeテキストは、その保存形式を見分けやすくするため、最初にUnicode文字の「\uFEFF」を付けることがある。これがBOM(バイトオーダーマーク)である。文字の値としては「\uFEFF」ひとつだが、ファイルへの保存形式によって次の違いが出る。

  • UTF-16BE
    -- 16ビットをビッグエンディアンで保存するため、BOMは(fe, ff)となる。
  • UTF-16
    -- リトルエンディアンで保存するため、BOMは(ff, fe)の順になる。
  • UTF-8
    -- 可変長データに変換するため、BOMは(ef, bb, bf)の3バイトになる。

UTF-16BEとUTF-16は、データ内容からどちらなのか判別するのが原理的に難しいため、BOMの付加が強く推奨されている。いっぽうUTF-8の場合はBOMがなくても判定は容易だし、プログラムによっては未対応だし、あまりBOMを付けるメリットはない。

●いろいろな形式のUnicodeファイルを作る

実際に各種の形式のUnicodeファイルに触れてみるとわかりやすい。せっかくだからC#でいろいろなファイルを作ってみよう。コードは下記。今回はコンソールアプリケーションにしてみた。

  1. 「ファイル(F)」→「新しいプロジェクト(P)」で、プロジェクト作成ウィンドウを開く
  2. カテゴリ「Visual C#」で、テンプレート「コンソールアプリケーション」を選ぶ
  3. 名前を「EncodeFiles」と入力してプロジェクトを作成する
  4. Program.csを開き、次のコードを入力する

実行すると、PCのデスクトップに「WorkFolder」というフォルダができ、さらにその中にいろいろなエンコードのHTMLファイルが作られる。

●次回の予告

BOMの処理の続き。

2015年12月5日土曜日

P011-ネットのテキストを読み込む

今日の目標→

ネットから画像が読み込めたら、次はテキストの読み込みだろう。

●MyLibの拡張

ネット上の日本語テキストって、ほぼUTF-8に統一されたのかな? でもやっぱり、今でも文字コードの判別は避けて通れないだろうなあ。 昔作った文字コード判定クラスがあるので、これを流用しよう。

というわけで、次のクラスをMyLibライブラリに追加する。

おそらく世の中にはもっと優秀なライブラリがあるだろうが、まあ自作のコードは愛着があるよね。 コードを入力し終えたらコンパイルして、「MyLibV03.dll」というファイル名で保存する。

●プログラム本体

  1. NetJob2という名前で、プロジェクトを作成する
  2. ソリューションエクスプローラの「参照」で、MyLibV03.dllの参照を追加する
  3. Form1.csを開き、次のコードを入力する

プログラムを起動し、テキストファイルのURLを入力して「テキストを読み込む」ボタンを押すと、上部のテキストボックスに内容が表示される。

テキストとは言うけどプレーンテキストだけじゃなくて、HTMLファイルも、RSSフィードも、中身は文字だけなのでこのプログラムで表示できる。

●要点の解説

WebClientクラスを利用してネットからデータを読み出すのは、画像の場合と同じだ。

ちょっと違うのは、前回はReadOpen()メソッドを利用しネットデータをストリーム形式でオープンしたが、今回はDownloadData()メソッドを利用して全データを一気にbyte配列に取得したことだ。メモリが少なかった昔はこういう大名プログラムは書かなかったが、時代は変わったのだ。

っていうか今考えたら、画像データもこのDownloadData()メソッドで取得すればよかったじゃない。そうすればストリームを閉じるの閉じないので、エラーが起きることもなかった…かもしれない。

取得した生のデータは、先ほどのMyLibライブラリのEncodingCheckerで文字コードを調べる。ちなみに使い方は、

Encoding enc = EncodingChecker.GetEncoding(バイト配列);

とすれば指定したバイト配列のエンコードを推測し、Encoding型の結果をencに入れる。あとは通常のEncoding.GetString()メソッドにより、適切な方法でstring型に変換可能だ。

2015年12月4日金曜日

バグ修正

今日の目標→

今日はバグの修正だけ。

●修正箇所

前回のForm1.csで、ReadNetImage()メソッドの次の部分に問題があった。

return Image.FromStream(stream);

これは次の3行のコードに差し替える。

MemoryStream mem = new MemoryStream();
stream.CopyTo(mem);
return Image.FromStream(mem);

そもそもWebClient.OpenRead()の説明で、「ストリームはすぐ閉じろ」的なことが書いてあるから、即クローズしていたのである。しかも、確実にストリームをクローズできるように、わざわざtry~catch~finally構文とか使ってた。

ところが、Image.FromStream()の説明を見たら、「読み込んだ画像の使用中はストリームを閉じちゃダメ」だって。なんだよそれ。

結局、ネットデータのストリームはメモリにコピーして接続を切る。そしてメモリストリームはクローズせず後始末をガベコレにまかせる、という折衷案にたどり着いたのであった。

バグ修正後のForm1.csが下記である。

旧版のプログラムはアニメーションGIFを読み込ませると不正終了した。今度は大丈夫だろう…たぶん…。

2015年12月3日木曜日

P010-ネットの画像を読み込む

今日の目標→

いまどきのプログラムは、やはりネットに接続できないと話にならない。今回はその最も簡単な例として、ネットから画像を取得してピクチャボックスに表示するプログラムを作ってみる。

●MyLibの修正

その前に、前回発見したMyLibライブラリの不具合(namespaceに全角文字を発見!)を修正しておく。コードを直すついでに、行数上限を変えるSetMaxLines()メソッドも追加した。

修正したライブラリをコンパイルしたら、「MyLibV02.dll」というファイル名で保存する。今後ライブラリの修正や機能強化のたびに、「V」の後ろの番号を増やしていく予定である。

●プログラム本体

  1. NetJobという名前で、プロジェクトを作成する
  2. ソリューションエクスプローラの「参照」で、MyLibV02.dllの参照を追加する
  3. Form1.csを開き、次のコードを入力する

プログラムを起動し、左下の入力欄に画像ファイルのURLを入力して「画像を読み込む」ボタンを押すと、ピクチャボックスに表示されるはずなのでお試しを。

今回から始まる「ネット接続」シリーズの土台となるプログラムなので、ウィンドウ構成もちょっと凝ってみた。基本は上下に分割されたウィンドウがあって、上部にデータ表示ウィンドウ(今回はピクチャボックス)、下部にレポート出力用のテキストボックスを配置している。

●要点の解説

ネット接続の中心になるのはWebClientクラスだ。このクラスは指定されたURLに接続し、そこからデータを読み出すという縁の下の作業を受け持つ。そのデータをどのように処理するかは、個々のプログラムの仕事である。

今回は画像の取得なので、Image.FromStream()メソッドでストリームからデータを読み出すだけでImage型の画像が作られる。

2015年12月2日水曜日

P009-DLLライブラリを使う

今日の目標→

自作のDLLライブラリを呼び出して使う。

●プロジェクトの作成

通常の「Windowsフォームアプリケーション」テンプレートで、「TextWork5」プロジェクトを作る。前回の作業のせいで、デフォルトは「クラスライブラリ」のテンプレートになってると思うので注意。

●「参照」の追加

プロジェクトが作られたら、自作DLLファイルの参照を追加する。

  1. ソリューションエクスプローラの「参照」を右クリック→「参照の追加(R)」
  2. 標準リストの中にないDLLは、下の「参照(B)」ボタンを押して自力で探す
  3. 前回作った「MyLib.dll」が見つかったら、「追加」ボタンを押す

これで「参照」にMyLibが追加された。

●MyLibを呼び出すコードを入力

Form1.csの最初に、

using MarugeProject

と書けば、MyLibで定義した公開メソッドが呼び出せるようになる。

なんだったら完全修飾名で「MarugeProject.RichReporter()」みたいに書いてもよい。

●実は重大なミスが

前回、MyLibのRichReporter.csのコードを書いたとき、

namespace MarugeProject

の「M」が全角でした…。なんか変だと思ったんだよ。しょうがないので、今回のTextWork5のコードでも全角「M」を使ってます。次回までにMyLibのほうを修正しなくては…。

2015年12月1日火曜日

P008-DLLライブラリの作成

今日の目標→

自作クラスをDLL形式のライブラリにする手順を述べる。 やたら長くなったけど、このライブラリは後でいろいろ機能を追加して育てていく土台になるので頑張る。

●ライブラリ用のプロジェクトを作成

DLLライブラリを作るには、いつもの「Windowsフォームアプリケーション」ではなく、次のように「クラスライブラリ」のテンプレートを選ぶ。

  1. メニューバーから「ファイル(F)」→「新しいプロジェクト(P)」で、プロジェクト作成ウィンドウを開く
  2. 左のカテゴリで「Visual C#」、右のアイコンで「クラスライブラリ」を選ぶ
  3. 名前を「MyLib」と入力して「OK」ボタンをクリックする

●「参照」の追加

プロジェクトができたら、ウィンドウ右上のソリューションエクスプローラで、「参照」をダブルクリックすると、このプロジェクトで使える外部ライブラリの一覧が表示される。このままだと足りない感じなので、次の手順でライブラリを追加しておく。

  1. ソリューションエクスプローラの「参照」を右クリック→「参照の追加(R)」
  2. 左のカテゴリで「アセンブリ」、サブカテゴリ「フレームワーク」を選ぶ
  3. 右のリストで「System.Drawing」を探してチェックマーク
  4. 同じく右のリストで「System.Windows.Forms」を探してチェックマーク
  5. 「OK」ボタンを押す

これで「参照」にSystem.DrawingとSystem.Windows.Formsが追加された。今はこれで十分だ。後で足りないものがあったら、そのときにまた追加すればよろしい。

●不要なコードを削除

デフォルトで存在する「Class1.cs」は不要なので、ソリューションエクスプローラで消しておく。

Class1.csを右クリック→「削除(V)」

●自作クラスのコードを追加

ライブラリに自作クラスのコードを追加する。手で入力しても良いし、すでに存在するなら次のようにファイルから読み込んでも、どっちでも良い。

  1. メニューバーから「プロジェクト(P)」→「既存の項目の追加(G)」でファイルダイアログを開く
  2. "TextWork3"プロジェクトのフォルダを探す
  3. ファイル"RichReporter.cs"を選択する
  4. 「追加」ボタンを押す

●コードのnamespaceを変更

前回も書いたとおり、ライブラリのnamespaceは自分好みに変えて良い、というか変更すべきである。本当は中二病的なカッコいい名前が好きなんだけど、まあ妙にこだわると後で恥ずかしいからな…。というわけで好きなピザにちなんで、

namespace MarugeProject

に決定。読み方は「マルゲプロジェクト」ね。変更後のコードを下記に示す。

namespace以外に変更した箇所はない。

●プロジェクトをコンパイルしてDLLファイルを作る

クラスライブラリの作成プロジェクトは、いつものように「開始」ボタンで実行はできない。その代わり次の方法でコンパイルする。

メニューバーから「ビルド」→「ソリューションのビルド」を選択

コンパイルが終わると、プロジェクトのフォルダの下、bin\Debugサブフォルダに「MyLib.dll」というファイルが作られる。これがDLL形式のライブラリである。

なお、bin\Debugサブフォルダは一時的な保管場所で、たとえば「ビルド(B)」→「ソリューションのクリーン(C)」メニューを実行すると削除されてしまう。なので完成したDLLファイルは適当な別フォルダにコピーしておくとよいかも。

●次回の予告

うわー記事が長くなりすぎた。今日はここまでといたします。作成したDLLライブラリを呼び出して利用する手順は、次回で書くことにします。

あと、本ブログの記事で作ってるプログラムをアーカイブして、ダウンロードできる方法を考えています。どこにファイルを置くかが問題だ。