Emacs のファイル差分表示(ediff, diff)機能の使い方

今回は Emacs でファイルの差分を表示する機能の紹介です。
Emacs で差分が表示できればそのまま編集することができますし、 表示も差分ビューワー並みにわかりやすく表示できます。

なお、Emacs で diff の機能を使うためにはコマンドラインの diff プログラムが必要となります。
Unix 系ではデフォルトで入っていると思いますが、 Windows ではインストールする必要があります。インストール方法については以前の記事をご覧ください。

ediff (Emacs Diff)

ediff の機能によって差分ビューワーのように差分を表示することができます。
emacs_diff_ediff.png

ediff の開始

ediff は比較対象を指定して開始します。比較対象にはファイルやバッファーなどを指定可能です。
コマンドはキーに割り当てられていないので、 M-x の後に次表のようなコマンド名を入力します。
コマンド 対象
ediff-files ファイル
ediff-buffers バッファー
メニューからも実行可能です。 これら以外にもいろいろあるので、他ものはそちらで確認して下さい。
 [Tools] -> [Compare (Ediff)] 

表示時の操作

ediff 実行中は操作用バッファー内でキーを入力します。
使用するキーをいくつか紹介します。詳しくはヘルプを見て下さい。
キー 機能
p または [Back space] 前の差分位置に戻る
n または [Space] 次の差分位置に移動
a 現在位置の内容をバッファー A から バッファー B にコピー
b 上記の逆
? ヘルプの表示
q ediff の終了

設定

いつのバージョンからか忘れましたが、 デフォルトでは操作用バッファーが別フレームとして分かれるようになってしまいました。
個人的には、これだとバッファー間の移動が面倒で使いづらいです。 設定で最初のスクリーンショットのように 1 つのフレームにすることができます。

設定には Emacs のカスタマイズ機能を使います。
  1. M-x customize-group のあとに ediff-window
  2. [Ediff Window Setup Function] で [Single Frame] を選択
  3. 設定、保存
emacs_diff_settings.png

eshell 上での diff

Emacs でのコンソールである eshell から diff 機能を使用する方法についても紹介します。

diff コマンドの実行

eshell 上で diff を実行すると、結果を別 Window に表示します。
emacs_diff_eshell.png

1 つずつのファイルの場合は ediff の方が便利ですが、ディレクトリー(フォルダー)ごとの比較といった場合に重宝します。

diff 結果のバッファー(*Diff*)では以下のような操作が可能です。
キー 機能
M-p 前の差分位置に戻る
M-n 次の差分位置に移動
M-P 前のファイルの差分位置に戻る
M-N 次のファイルの差分位置に移動
? ヘルプの表示
他の操作に関してはヘルプを見てください。

また、私が以前作成した emacs-lisp を使うと n, p での移動も可能となります。

eshell から ediff を呼び出す

eshell にコマンドを追加することによって、 eshell 上から ediff-files を呼び出すことができます。
 ~/cs/i18n/WpfI18n/Properties $ ediff Resources.resx Resources.ja-JP.resx
 #<buffer *Ediff Control Panel*>
やり方については、 以前の eshell のカスタマイズ記事をご覧ください。
スポンサーサイト
 

WPF での文字列リソースの利用と国際化

今回は WPF で文字列リソースを使う方法と国際化に関する記事です。

WPF では、文字列リソースを使ってアプリケーションを作っておけば、簡単に国際化することができます。
ここで "文字列リソースを使う"といっているのは、文字列をリソースファイルにまとめて定義し、 それを WPF のラベルやコード内のメッセージに使うことを意味しています。
"国際化する予定はない"という場合も多いとは思います。 その場合でも、コード内に文字列を直接書くのはあまり良くないので、 リソースを使ったコードと文字列の分離だけはやっておいた方がいいでしょう。


これから、サンプルアプリの作成手順にあわせて、リソースの利用法と国際化について説明していきたいと思います。

国際化の方法については以下のサイトを参考にさせて頂きました。参考というよりほぼ一緒ですが、ちょっと視点を変えて解説したつもりです。

文字列リソースの使用

最初はまだ国際化せずに、文字列リソースを利用しただけのアプリケーションを作成することにします。

まず "WpfI18n" という名前で [WPF アプリケーション] を新規作成します。
初期の構成は次のようになっています。
cs_i18n_startproj.png

リリースファイルの登録と作成

リソースファイルを使えるようにするためには、 App.xaml にリソースを登録する記述を追加します。

App.xaml :
 <Application x:Class="WpfI18n.App"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:properties="clr-namespace:WpfI18n.Properties"
              StartupUri="MainWindow.xaml">
     <Application.Resources>
         <properties:Resources x:Key="resources" />
     </Application.Resources>
 </Application>
Resources.resx がリソースファイルです。これを編集して文字列リソースを定義していきます。
国際化時のデフォルトの文字列とするので、英語版で作成します。
English resource

アクセス修飾子は Public を指定します。
ここでいったんビルドを行なって下さい。リソースを編集した場合、ビルドしていないと選択時の候補などが更新されないことがあります。

レイアウト

MainWindow のサイズを適当に変更し、ボタンを一つ配置します。 名前は buttonGreet としておきます。
cs_i18n_layout.png

サンプルなのでてきとうですが、実際に国際化するには Panel などのコントロールを利用して、 サイズや位置を直接指定しないようにする必要があります。 Qt, Gtk+ といった Unix 系のツールキットでは、伸縮を考慮したレイアウトの方が普通です。
Windows ではようやく WPF からちゃんと対応しました。 しかし、 VS の GUI ビルダーでは勝手にサイズなどをいれてしまうため、 いちいち [リセット] していく必要があります。 この辺はもう一息といったところです。

UI からのリソース利用

[Content](表示内容)を文字列で直接入力するのではなく、 データバインドを利用する ところがポイントです。
サンプルでは、ボタン(buttonGreet)とウィンドウのタイトルを文字列リソースで指定しています。

Content のところでデータバインドを設定するダイアログを開きます。
ここで [StaticResource] を選び、各リソース名を選択します。

cs_i18n_databind_menu.png cs_i18n_databind_dialog.png

VS2010 の場合はちょっとわかりづらいですが、 [ソース] で [StaticResource]、 [Application.Resources]と順に選択してから、[パス]で各リソース名を選択します。
データバインドダイアログ(VS2010)

コードからのリソース利用

コードから文字リソースを利用する例も挙げておきます。
ボタン(buttonGreet) をダブルクリックして、コールバック用のメソッドのひな形を追加します。 そこに以下の記述を追加すれば、 buttonGreet を押すと文字列リソースで定義されたメッセージを表示するようになります。

MainWindow.xaml.cs :
        private void buttonGreet_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(Properties.Resources.MessageHello);
        }
ここでビルドして、実行してみてください。 文字列リソースで定義した文字がアプリケーションで使用されていることが確認できると思います。
cs_i18n_exec.png

国際化

リリースファイルの作成

次の手順で、[ソリューション エクスプローラー] の操作を行い、日本語の文字列リソースファイルを作成します。
  1. Resources.resx をコピー
  2. プロジェクトに対して貼り付け
  3. Resources.ja-JP.resx と名前を変更
  4. [Properties] に移動
cs_i18n_proj_ja.png

作成したリソースファイルを開き、値を日本語に変更します。 このときアクセス修飾子は [コード生成なし] にします。
cs_i18n_res_ja.png

ビルドして、実行してみてください。これだけで日本語に変更されているはずです。
cs_i18n_exec_ja.png

リリースファイルの仕組み

英語で表示されていた場合の仕組みは次のようになっています。
  1. ユーザーの設定は 言語:日本語(ja)、地域:日本(JP)
  2. ja-JP のリソースを探す
       → みつからない
  3. デフォルト(Resources.resx)のリソースを使用
  4. 英語で表示
Resources.ja-JP.resx の作成後は、"ja-JP" のリソースが見つかり、日本語で表示されるようになります。


"ja-JP" というのは、 言語、地域を指定する Culture 名です。どのよう文字を指定するかは以下のサイトで確認できます。 通常の開発では文字列リソースは追加や削除などの編集を繰り返すことになると思います。

例えば、 日本語のリソース定義が足りていなかったとしたら、どうなるでしょうか?
この場合はその文字だけデフォルト(英語)のリソースが使用されます。

このように文字列リソースはファイル、項目などが見つからない場合にはデフォルトが使われます。 日本語をデフォルトにしていると英語環境では文字化けする危険があります。 デフォルトは英語 の方がいいでしょう。 (逆に英語が混じっていても、まずバグとは言われません)

なお、リソースファイル(.resx)の実態は XML フォーマットのテキストファイルです。
テキスト差分表示のツールなどで対応を確認することもできます。

生成ファイル

日本語用の文字列リソースファイルを作ってビルドすると、 exe のところに次のようなファイルも生成されます。
リリースする場合にはこの構成でリソース用の dll を付けてリリースしてください。
(Debug|Release)/
  ├ WpfI18n.exe
  └ ja-JP/
      └ WpfI18n.resources.dll

国際化のテスト

日本語のリソースを作成したら、日本語で表示されるのはいいのですが、 今度は英語が表示できません。表示言語を切り替えて、各言語での表示を確認する方法について説明します。


ちなみに、 英語と日本語だけでいいということであれば、"ja-JP" のフォルダーを削除すれば、 英語で表示することも可能です。

ユーザー環境の変更

言語、地域はユーザーごとに設定します。
これは [コントロールパネル] から変更することができます。

コントロールパネルの表示スタイルによっても変わりますが、 [表示言語の選択][地域と言語] の項目を選択すると、 ダイアログが表示されます。 ここで表示言語を変更します。
cs_i18n_setlang.png

ただし、他言語が一つもインストールされていないと選択項目は表示されません。 インストールできるかどうかは OS のタイプ(Ultimate など)によります。
cs_i18n_setlang.png

言語の設定を反映させるにはログオフをする必要があります。 ちゃんとテストする場合などはテスト用のユーザーを作り、 それを切り替えて確認することになるかと思います。

ただし、開発中の確認などではそれも面倒です。 次節で起動時にプログラムの表示言語を変える方法を説明します。
こちらは他言語がインストールされていなくても表示することができます。

起動時に表示言語を変えるコードを加える

次の方法でカルチャー名を指定して起動できるような修正を行います。
  • 環境変数
  • コマンド引数
サンプルでは両方できるようにしていますが、好きな方を使用してください。
さらに改造すれば、ファイルから読み取ったり、保存していた設定(次回の起動時から有効)で指定したり といったこともできるのではないかと思います。


起動時に実行するメソッドを追加
アプリケーションの XAML に Startup の要素で起動時に実行するメソッドを追加します。

App.xaml :
 <Application x:Class="WpfI18n.App"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:properties="clr-namespace:WpfI18n.Properties"
              StartupUri="MainWindow.xaml" Startup="Application_Startup">
     <Application.Resources>
:
VS 上で追加すれば、関数名やコードへのひな形も自動的に追加されます。


カルチャー情報の変更
追加した起動時のメソッドで現在のスレッドのカルチャー情報を変更します。
GUI の表示を変えるため、 CurrentCulture だけでなく CurrentUICulture も変更しているところに注意してください。

App.xaml.cs :
         private void SetCurrentCulture(string culname)
         {
             Thread.CurrentThread.CurrentCulture = new CultureInfo(culname);
             Thread.CurrentThread.CurrentUICulture = new CultureInfo(culname);
         }
 
         private void Application_Startup(object sender, StartupEventArgs e)
         {
             // 環境変数を使用
             string langstr = System.Environment.GetEnvironmentVariable("TEMP_LANG");
             if (langstr != null)
             {
                 SetCurrentCulture(langstr);
             }
 
             // 引数を使用
             if (0 < e.Args.Length)
             {
                 SetCurrentCulture(e.Args[0]);
             }
         }
スレッドやカルチャー情報を使うための名前空間も追加する必要があります。
 using System.Threading;     // 追加
 using System.Globalization; // 追加

実行
次のように引数を指定して実行すると、英語版画面が表示されます。
 ~/cs/i18n/WpfI18n $ ./bin/Debug/WpfI18n.exe en-US
ただし、サンプルでは en-US のリソースを表示しているわけではありません。 en-US のリソースがないため、デフォルトのリソースを使用した結果、英語版で表示されています。

サンプルコード

作成したサンプルアプリのコードもあげておきます。 なお、サンプルを順に作らずに、サンプルコードをそのままビルドして実行すると XAML の解析で実行時例外が発生する時があります。
この場合、 改行を足すなど、なんでもいいので、 MainWindow.xaml.cs ファイルをちょっと修正して、ビルドしなおすと解消することが多いです。 私も原因はよくわかってないのですが...

追記 2013-09-17
resx ファイルを StaticResource から利用するとどうしても出てしまうバグのようでした。
マークアップ拡張を使って resx ファイルを利用する方法の記事を追加しました。 また、国際化の切り替えのコードで Thread.CurrentThread.CurrentUICulture しか設定していなかったので、CurrentCulture の方も設定するように変更しました。

 

Windows でも意外と役立つ gzip 圧縮を C# から使う

gzip といっても Windows ではなじみがない人が多いでしょう。
しかし、 gzip は意外と使えるヤツです。 しかも .NET では gzip の 圧縮、展開を行うのに便利なクラスが用意されています。
そこで今回は Windows でも意外と役に立つことを紹介した後、 C# での gzip の圧縮、展開方法を説明したいと思います。

gzip とは

gzip は GNU ZIP の略で、 gzip という圧縮コマンドやその圧縮方式(圧縮後の拡張子は .gz) を指します。 Unix 系ではよく使われている圧縮方式です。
一方 Windows では ZIP がよく利用されています。 gzip と ZIP はともに Deflate という圧縮アルゴリズムを使用します。 ただし、ZIP は複数ファイルをまとめる機能を持っているのに対して、 gzip は単にデータ(ファイル)を圧縮するためのものです。 このため、ファイルをまとめる機能を持つ tar と合わせて(.tar.gz、 .tgz)使用されることが多いです。

なお、 .NET 4.5 であれば、 ZIP の圧縮、展開も対応したらしいです。 ただし、 私の場合は Windows 7 、 .NET 4.5 、 VS2012 Express の環境でやっていみたのですが、 ZIP 用のクラスは使えませんでした。

gzip の用途

先ほどの説明だと単に gzip の機能が ZIP に比べて劣っているという印象を受けた人もいるかもしれません。 確かに ZIP は便利だし、よく使われていますが、 シンプルなものにはシンプルなりの用途があります。

通信データの圧縮

gzip コマンドを使ったことがないという人は多いかもしれませんが、 実はかなりの人が知らない間に gzip 圧縮を利用しています。
というのも、見かけ上はわからないようになっていますが、 HTTP 通信で gzip 形式の圧縮がよく使われているためです。

使われる場合は次のような手順です。
  1. サーバー上には *.html.gz, *.css.gz といった圧縮したファイルを置く
  2. ブラウザーが対応していれば、 圧縮されたまま通信 (最近のブラウザーはほとんど対応)
    • 対応してない場合はサーバーで展開
  3. ブラウザー側で展開して表示
HTTP 通信に限らず、 マシンパワーはあるのに通信が細いということはよくあります。 gzip はこういった場合の 通信データの圧縮 に役に立ちます。
通信相手が Windows でない場合でも、そちらは zlib などを使えば、 圧縮、展開は結構簡単に実装できます。

ファイルフォーマット

アプリケーションを作成した場合などで、独自フォーマットのファイルを作ることはあるでしょう。
この時、陥りやすいトラップが "ビットレベルで詰めたら、サイズが得になっていいのではないか" という考え方です。
これは間違いではないのですが、実装がかなり大変になる上に、 たいていは効果も薄いです。

それをやるくらいなら、作りやすいフォーマットにして、全体または部分的にデータを圧縮した方が、 作成者にも使用者にも嬉しいフォーマットになります。
実際に svgz や PNG などでは、そうやって gzip(Deflate) が使われています。

使用クラス

データ圧縮、展開用のクラスとしては DeflateStream と GZipStream の 2 つのクラスがあります。 gzip クラス


gzip も Deflate アルゴリズムなので、 DeflateStream と GZipStream はほとんど同じものです。
ただし、 GZipStream の方が 2 つ利点があります。
  • データ破損を検出するための巡回冗長検査 (CRC) 値を含んでいる
  • 拡張して Deflate 以外のアルゴリズムに変更することができる
GZipStream クラスは Stream という名前の通り、 IO Stream のような使い方ができます。
これをフィルターのように入出力のストリームの間にかませることによって、 圧縮・展開を行うことができます。

ちなみに Unix でも gzip コマンドはフィルターとしてよく使われています。

実装

引数に渡すファイルによって次のような動作するコマンドラインプログラムをサンプルとして作ってみました。
引数 動作
.gz で終わるファイル 展開
.gz 以外のファイル 圧縮

ソースファイル : コンパイル:
 > csc GZipSample.cs
実行結果 :
~/cs/gzip $ ./GZipSample.exe sample.txt 
Input      : sample.txt
Compress   : sample.txt.gz
~/cs/gzip $ ls
GZipSample.cs  GZipSample.exe  sample.txt  sample.txt.gz
~/cs/gzip $ rm sample.txt
~/cs/gzip $ ls
GZipSample.cs  GZipSample.exe  sample.txt.gz
~/cs/gzip $ ./GZipSample.exe sample.txt.gz 
Input      : sample.txt.gz
Decompress : sample.txt
~/cs/gzip $ ls
GZipSample.cs  GZipSample.exe  sample.txt  sample.txt.gz

以下に圧縮、展開の処理部分を GZipStream.cs から抜粋したものをあげます。
なお、 using に関して詳しく知りたい方は次の記事を参考にしてください。 圧縮 :
public static void GZipCompress(string srcpath, string gzpath)
{
    // 入力用ストリーム
    using (FileStream fin = new FileStream(srcpath, FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        // 出力用ストリーム
        using (FileStream fout = File.Create(gzpath))
        {
            // 出力用ストリームに gzip ストリームのフィルターを付ける
            using (GZipStream gzout = new GZipStream(fout, CompressionMode.Compress))
            {
                fin.CopyTo(gzout);
            }
        }
    }       
}
展開 :
public static void GZipDecompress(string gzpath, string destpath)
{
    // 入力用ストリーム
    using (FileStream fin = new FileStream(gzpath, FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        // 出力用ストリーム
        using (FileStream fout = File.Create(destpath))
        {
            // 入力用ストリームに gzip ストリームのフィルターを付ける
            using (GZipStream gzin = new GZipStream(fin, CompressionMode.Decompress))
            {
                gzin.CopyTo(fout);
            }
        }
    }       
}
GZipStream はストリームとして実装されているのが、よくできている点だと思います。
サンプルではファイルのストリームでしたが、 Stream を継承したクラスであれば、同じようにフィルターとして使うことができます。

通信部分をNetworkStream クラスを使って実装していれば、 圧縮したデータによる通信機能も簡単に追加することができるのではないかと思います。


 
このページをシェア
アクセスカウンター
アクセスランキング
[ジャンルランキング]
コンピュータ
39位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
4位
アクセスランキングを見る>>
カレンダー(アーカイブ)
プルダウン 降順 昇順 年別

05月 | 2013年06月 | 07月
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 - - - - - -


はてな新着記事
はてな人気記事
ブロとも申請フォーム
プロフィール

yohshiy

Author:yohshiy
職業プログラマー。
仕事は主に C++ ですが、軽い言語マニアなので、色々使っています。

はてブ:yohshiy のブックマーク
Twitter:@yohshiy

サイト紹介
プログラミング好きのブログです。プログラミング関連の話題や公開ソフトの開発記などを雑多に書いてます。ただ、たまに英語やネット系の話になることも。