cdif アップデートしました
久しぶりに cdif コマンドを使おうとしたら $*
なんか使ったらいかんよと動いてくれなかった。
なにしろ、作ったのは1992年で、最後に更新したのが2003年という骨董品のコマンドなので、perl4 の仕様で書いてある。
翻訳作業などでは、文章の変更点を確認したいことがよくある。
diff を使えば、行単位での違いを表示してくれるのだが、1行が長くてその一部だけが変更されているような場合には、変更点を探すのが大変だ。
cdif を使うと、行の中で異なる部分をハイライトしてくれる。
フィルタとして動作するので、diff の出力をパイプで流し込めばよくて、通常の形式以外に -c
や -u
形式にも対応している。
元はと言えば、FrameMaker だったか何かで書かれた英文マニュアルの更新作業のためにやっつけで作ったものだ。
ちょうど、UCB の CSRG と 4.4BSD の開発をしている時で、Berkeley から Cupertino に帰るフリーウェイを走りながら実装方法を考えて、帰ってから深夜に作った記憶がある。
滅多に使うわけではないがないと困るので、まずは、今時、他にもっといいツールがあるんじゃないかと思って調べてみた。
wdiff
- https://www.gnu.org/software/wdiff/
- C
- 独自形式
- Unicode 対応してないっぽい
- ワードの区切りはスペースだけで、変更もできなさそう
- 所感
- スペース区切りだけでは日本語の文章に使うのは無理
- 出力が見にくい
jwdiff (追加)
- http://fumiyas.github.io/2013/12/12/jwdiff.sh-advent-calendar.html
- シェルスクリプト
- wdiff の区切りが使えないので、mecab で分かち書きするシェルスクリプトを作ってる人がいた。
- mecab でトークンに分けたものをタブでつなぎ、wdiff にかけた後でタブを削除するというもの
- 当然元の文章にタブが入っていると困るわけだが、特定用途には使えると思われる
- トークンを1行に変換し、diff した結果を反映するという方法も考えられるが、これはまさに cdif がやっていること
colordiff
- http://www.colordiff.org/
- Perl
- diff の出力に行単位で色を付けるだけ
- wdiff の出力も受け付けるが、やはりただ色を付けるだけ
- 特に Unicode 対応はしていないようだが、行指向なので普通に動作する
- 所感
- なんでこんなもののために独自ドメイン取ったんだろう?
diffc
- https://code.google.com/p/diffc/
- Python
- Unicode 対応なし
- 単語ではなく文字単位で処理するので出力が見にくい
- デフォルトの色使いは非常に見にくい
- 遅い
- 所感
- 労作ではあるのだが、どうも実用のために作ったのではない気がする
- Python だし、改造するつもりがあれば、わりと筋がいいかもしれない
- でも、ソースがチョー長くて読む気にならない
- 動作が遅いので、大量のデータを処理するのには向いていないかも
git-diff
- --color で色分けしてくれるが、これは行単位
- --word-diff で、wdiff 形式で出力
- --word-diff-color で変更部分を色分けして出力
- Unicode は扱えるが、単語の区切りは空白
- そのため日本語は全部1ワードとして扱われてしまう
- 機能的には総じてよくできているが、通常の diff 形式には対応していないし、フィルタとしても動作しないような気がする
- 多少手を入れればコマンド化は難しくないと思う
- wdiff 形式を diff 形式に変換することは簡単だが、それでは diff 形式の出力を処理することはできない
diff-highlight.pl
- https://github.com/git/git/tree/master/contrib/diff-highlight
- 2011年
- Perl
- git で使うために作られたもの
- フィルタとして機能する
- git diff --color の出力も処理できる
- コマンド自体は Unicode 未対応だが、perl -CSDA で実行すれば問題なく機能する
- コードは極めて短く、処理も単純
- 問題点
- diff -u 形式にしか対応していない
- 変更前後の行数が同じものだけを処理する
- プログラムの変更点を見るにはいいが、文章の変更部分をチェックするのには向いていない
- 文字単位で処理するため、単語の変更がわかりにくい (diffc と同様)
- アルゴリズムが単純なので、パターンによってはうまく処理できず、変更部分の抽出に失敗する
- 所感
- ちょっとしたコードの変更をわかりやすくすることができ、実装も簡潔かつ高速で優れた実装だが、文章の校正のような用途には向いていない。
- パラグラフが1文になっているワープロ原稿のようなもので、修正点が微細な場合には使えると思う。
Python 版 diff-highlight
diff-highlight の機能が意外にしょぼいと思った人は他にもいるようで、拡張してくれていた。
- https://pypi.python.org/pypi/diff-highlight/
- blog
- 2013年
- Python
- Unicode 対応
- diff -u 形式にのみ対応
- 所感
- 実は、cdif を更新してからこの記事に気がついた
- 文字単位の比較なので、文章に適用するのに最適ではない
- 最大の問題は出力の順序を変更してしまうことだが、後で元に戻すのは簡単にできるだろう
- 他の diff 形式に対応して、単語を認識するようにすれば汎用コマンドとして使える可能性あり
ediff.el
- emacs で動作する
- 日本語には対応している。
- ワードは句読点で区切られる感じなので、荒すぎる。
- 所感
- 昔見た時にはよくできていると関心したのだが、実用的に使ったことはなかった
- 改めて使ってみると、そんなには関心しない
- 単語の区切りが荒すぎるせいもあるのだろうが、どちらかというとウインドウのインタフェースが使いにくいのだと思う。何がいけないかを分析するためには時間が必要だが、その労力に見合うか不明。
cdif
というわけで、どうも自分の目的にちょうどいいコマンドが見当たらないので、cdif を更新することにしました。 作ったのはモノクロ時代で、アンダーラインと反転で表示するしかなかったが、近代的にカラー化することに。 基本的な機能は20年前と変わっていなくて、モダンなプログラミングスタイルに書き換えて Unicode 対応した以外は、主にコスメティックな修正です。
- https://github.com/kaz-utashiro/cdif
- 1992年
- Perl
- Unicode 対応
- ワードは alphanumeric、漢字、平仮名、片仮名の連続
- それ以外の文字は、同じ文字が連続する場合はワードとして処理
- ついでにハングルも入れてある
- ヨーロッパ系はよくわからないので未対応
- 教えてくれたら入れます
- 中国語は漢字の連続をワードで処理すると困るかも
- 文字単位で比較したい場合は
-B
オプションを使う - 色使いは OS X のターミナルでチューニングしてある
- 一応 --colormap というオプションで変更可能
- 仕様が固まっていないのでマニュアルには書いていません
- 変えたい人は、ソースを書き換えちゃった方が早いです
- そこそこ高速に動作
- テキスト全体に色を付けるのは、見た目は派手だけど実用的に必要かというとそうでもない気がしてやっていない
- ハイライトから抜ける時の処理が面倒なだけでもあったりはする
- 実装は手抜きで、バックエンドで diff コマンドを使っているので、多分 Unix 系 OS のみ対応
greple -Mdiff
さて、ついでというわけではないが、単に diff の出力に色を付けるだけなら greple のマクロだけでできちゃうぜということで、diff 用のモジュールを書いてみた。 いかが?
Greple command module for colorise diff output.
(2018-3-27 更新)
greple --word-diff-color 相当
git diff で、--word-diff-color を付けると wdiff のシンボルを削除して色づけして表示してくれるので、使い方によっては見やすくなる。
ちょっとした関数を定義すると greple でも同じことができる。
コードは短いがやっていることは、少々複雑である。
パラメータとして連想配列の要素が渡され、matched
というキーを持つ値にマッチした範囲が入っている。
テキスト全体は $_
に入っているので、これを書き換えれば出力を修正することができるのだが、位置が変わってしまうと、それに合わせて範囲の指定も修正してあげないといけない。
先頭から書き換えると後ろが狂ってきちゃうので、配列の最後からテキストと範囲の両方を修正してあげればいいという寸法だ。
ちなみに matched の要素は開始位置、終了位置以外に、パターンのインデックスも付いているので注意。
出力は通常の機能で行うので --print print_wdiff
に --continue
オプションも付けて使います。
見た目を気にしなければ wdiff -t
を使えばいいので、機能自体はご愛嬌だが、print 関数の例としてはなかなかよいのではないかと。