FastGrepReplace 2.50 リリース

秀丸用マクロ、FastGrepReplace を 2.50 にバージョンアップしました。

G‚܂邨‚̃z[ƒ€ƒy[ƒW(ƒTƒCƒg[Šé‰æ)|FastGrepReplace 2.50 wgrep‚µ‚Ä‚Ü‚Æ‚ß‚Ä’uŠ·x

質問や不具合報告があれば、気軽にコメントしてください。

以下蛇足です。

今回のバージョンで苦労したこと

FastGrepReplaceは、2003 年開発当初「高速に大量ファイルを置換する」というのが目的だったのですが、C++ で開発すれば、秀丸マクロのみで動作させるよりは高速に動作するのは当たり前だったりします。

当初は「おぉ、速い速い♪」で満足していたのですが、この速さをアドバンテージに、多少いろいろな処理を追加したとしても、体感ではそれほどわからなかったりするわけです。ちなみに処理中、最も時間がかかるのはファイル入出力部分です。

追加しているいろいろな処理というのは、文字コード判定置換候補のチェックです。

文字コード判定は NKFWKF というライブラリに、それらを補う形で独自の判定処理を追加しています。NKFWKF も、その登場が早期だったため、Unicode の判定が行えません。FastGrepReplace では、Unicode に特化して文字コード判定を行います。

ちなみに FastGrepReplace 1.xx の頃、シェアウェア文字コード判定ライブラリを購入したのですが、全然ダメダメでした。この手のライブラリは多くのユーザに叩かれてナンボなので、作者がどれだけテストしたとしても、フリーで公開されているライブラリの品質には遠く及びません。ということで FastGrepReplace も多くのユーザさんによって品質が支えられています。

さて、FastGrepReplace 2.00 は 2 年ほど前に完成させたのですが、この時の対応が今見ると結構ひどかったです。というのも、FastGrepReplace 2.00 は Unicode に対応したバージョンでもあるのですが、Unicode で扱える文字が日本語に限定されています。せっかく Unicode で多国語が混在できるのに、日本語限定なんです(もっと細かく言うと、UTF-16 は日本語限定で、UTF-8 はその限りではありません)。

当時の僕も、多くのユーザさんも、実は日本語限定で問題なかったりするんだと思います。いや、UTF-16 というテキストを操作すること自体、機会がないのかもしれません。うん、たぶんそうでしょう。

僕は今、中国語のテキストを扱う機会が多くなり「2 年前の俺は何を考えてこんな仕様にしたんだ?」と憤慨し、重い腰を上げて本当の Unicode 対応に取り組むことにしました。

ただ、FastGrepReplace の内部保持形式が char の配列で、かつ 2.00 の頃は UTF-16 と判定したら、WideCharToMultiByte でさくっと CP932 に変換していました。完全な Unicode 対応を行う場合、この部分を完全に見直さなきゃならないわけです。

「一から作り直そうか?」とも思いましたが、それはとても気力が足りない。結局、置換で変更される行のみ char 配列に加え wchar_t 配列を持つように内部保持形式を変更しました。

動作が複雑になったので、テストケースを増やし、また、大量ファイルに大量置換、元通りにする置換を繰り返し、正しく元に戻るテストを繰り返しました。

実装が終わり、約 1 ヶ月、自分で通常用途に使ってみて、問題がなさそうだと判断し、リリースすることにしました。

実装も苦労しましたが、テストも苦労しました。

安全度アップ

秀丸の仕様で、grep の結果には2048バイト未満までしか表示されません。要するに 2048 バイト以上の非常に長い行が grep でヒットした場合、その一部しか grep 結果に取り込まれないことになります。

そうするとどういうことが発生するかというと、grep で取り込まれた部分的な文字列に置き換わってしまうわけです。

この問題を解決するために、置換対象行が 2048 バイト以上あるかどうかを置換時にチェックするようにしています。もし 2048 バイト以上ある行を置換しようとすると、上のようなダイアログがポップアップされます。

秀丸の仕様で、CP932 範囲内の文字は CP932 相当のバイト数、それ以外は 4 バイト、という内部計算を行うので、FastGrepReplace では、大まかに文字数を数えたのち、2048 バイトをオーバーする可能性がある場合に限り、置換対象行の文字を一文字ずつ CP932 範囲内かどうかチェックしています。

それでもチェック関数が速度優先(サイズ犠牲)で、かつ C++ で実装されているので、速度的に気になるということはないと思います。

というか、通常使用の範囲ではそんなに長い行が対象になることは稀でしょうけど。

開発を通じて

このマクロは 99% が C++ で実装されているので、開発を通じて C++Windows に関する知識が蓄積できました。特に DLL を実装するにあたってのノウハウが身に付きました。

さて、FastGrepReplace 1.xx 当時は C で実装していました。

C を使用した理由は、C++ のオーバーヘッドが気になる、という些細な理由でしたが、はっきり言ってそのあるかないかわからない些細なオーバーヘッドを気にして、開発効率が非常に落ちていた気がします。

string とか vector とか、本当に便利です。