マクロ2.0。

テキストエディタQX いつまで経ってもベータ版ってことで>2.0
 QXのメーリングリストに適当な英文一括キャピタライズマクロを投げたはいいが、検証すればするほどボロが出てきて泣きそう。
 どうせならきっちり使えるものにしたいとは思うので、改めて仕様と条件を確認してみようかと思う。

これまでの経緯

 これまでキャピタライズに関しては「カーソル上の単語をキャピタライズして右の単語へ移動」する単純なマクロを使っていた。こんな感じ。

'カーソル上の単語の先頭を大文字に
proc main
@redraw = 0
@undoblock = 1
if @code = CODE_RETURN then @movenextlinecr
@moveleftchar
if @code = &h27 then
@moverightchar
@blockselectcursorword
@blocktosmall
@moverightword
else
@moverightchar
@BlockSelectCursorWord
@BlockToSmall
@MoveLeftWord
@charchangealpha
@moverightword
end if
@undoblock = 0
@redraw = 1
end proc

 これをCtrl Uに割り当てて押しっぱなしにすると、次から次へとキャピタライズされていくという寸法。実際、長文を処理しない自分にとってはそれで困らなかった。
 しかしそのマクロでは「アポストロフィ後は小文字に止めおきたい」とか「冠詞・接続詞は小文字で止めおきたい」とかの細かい要望に対応できてなかった。もちろん長文を処理する際には数十秒キーを押しっぱなしにしておく必要がある。
 というわけで ML で要望が出たついでに手をつけてみるかと思ったわけ。最近とある新聞社系ウェブサイトの構成変更にともない Internet Explorer の MenuExtension を更新しなきゃいけなかったりして、コーディングへの心理的ハードルが普段より低かったってのもある。仕事の忙しさとかももちろん影響して。年度末にぼーっとしてるなんてアリエナサス。

機能に関する検討

  1. キャピタライズしない(小文字で存置する)文字列群を外部ファイルで指定する
  2. 全文の一括処理、カレント行のみ処理、選択行のみ処理、選択文字列のみ処理を状況および初期設定・ダイアログ等で切り替える
  3. クリップボード内文字列の処理を可能にする

 クリップボード文字列の処理は自分にとって必須。もちろん iTunes とかのプロパティシート内「テキストボックス文字列」の処理が目標。曲名とかアルバム名とかでんな。もちろん選択→ホットキーで書き戻し。

選択の状態に関する区分

  1. 文字列選択状態(一行内)
  2. 文字列選択状態(複数行)
  3. 行選択状態(一行)
  4. 行選択状態(複数行)
  5. 無選択状態
  6. 文末まで選択している場合

 行選択の反映については、元にしたSiさん複数文字列一括置換マクロと同様「カレント行から置換を開始してマーク行で停止」する方法を踏襲している。そのままだと文字列選択を反映できないので「選択範囲のみを置換」する方法も加えているのだけど、両方がまざるのはメンテとパフォーマンスによろしくない影響がある。できれば一元化したい。
 いずれにせよキャピタライズの段階では逐次処理(単語を小文字化→先頭を大文字化→次へ)とならざるを得ないわけで、既存マーク退避などの手間を考えると全体を「逐次処理・選択範囲処理」という基本的な考え方で統一してしまっていいような気もする。
 箱型選択については「切り取り→処理済文字列を箱型貼り付けで書き戻し」してもよいのだが、現実的には「実行できません」で逃げるのが正しいスタンスか? リストの行頭記号を除外して処理したいケースなどもあり得るのだけれど、あまりやりたくない。

小文字で存置する特定文字列と例外処理

  1. 接続詞や冠詞・定冠詞は基本的に小文字化する
  2. 行頭にある場合はキャピタライズする
  3. 行頭から一個以上の空白に続く場合はキャピタライズする
  4. ピリオドから一個以上の空白に続く場合はキャピタライズする
  5. 後ろに a~z が続く場合は(違う単語となるので)キャピタライズする
  6. 後ろにピリオド,カンマなど記号が来る場合は小文字化する
  7. 後ろが改行の場合は小文字化する

 ここが一番のキモ。正直、日頃から英文に慣れ親しんでおられる人々の御協力を仰ぎたいところ。最近もっぱらROM状態だったQXメーリングリストにリプライしたのは、翻訳家が複数おられることが分かっているあの場所でなら実践的なアドバイスが期待できるかなー、なんて甘い期待を抱いたから。マジ甘かった。みんな年度末で忙しいのよきっと。
 今のところ上のリストのケースのすべてを処理できるようにするのが課題。要するに正規表現のパターンをどう落とし込むかという話なのだが、状況の区分ができてないので実装もアバウトという状況。
 小文字化する条件とみなすなら\([^\.] +\)string$\([^a-z]+\)というのが思いつく。つまり

  1. 単語の直前が一個以上のスペースで(Par-is とか Mo-on の一部ではない)
  2. その前はピリオド以外の文字で(処理対象の単語がセンテンスの頭ではない)
  3. 単語の直後は小文字の a~z 以外(Is-sue とか And-rew の一部ではない)

 ――という条件。しかしこれでは「行末でスペースやカンマも伴なわい接続詞」が取りこぼされる(文字列後に“来てはいけない”正規表現中に改行・行末を指定できていないから)。
 また、編集上の都合でセンテンス中で改行している場合も追いきれない。具体的には

My memories of schooldays in Japan is so sour, and[改行]
friends were always evil.

 みたいな文章を置換した結果が

My Memories of Schooldays in Japan is So Sour, And[改行]
Friends were Always Evil.

 なんてことになっちゃう。うまくねー。
 一時は「論理行末がピリオドかスペース以外で終了している場合はあらかじめスペースを付加して処理」なんてことも考えたのだが、置換やカーソル移動しまくりのマクロ中で「現状復帰」を必要とする処理はなるべくやりたくない。先のマーク処理忌避についても、マクロ実行以前に「ユーザが編集作業用として設定したマークを保存・復帰」させる作業が嫌なので避けてるという意味合いが強い。
 リストも困ったちゃんだ。例えば

a) The Kingdom of desire
b) Are You Gonna Go My Way

 なんていういかにもありそうなテキストを上記の設定で変換してみると、当然のように

A) the Kingdom of Desire
B) are You Gonna Go My Way

 という情けない結果が待っている。
 しかしこれを避けようとしてカッコを例外に加えたりすると、例えば

You kill the King (a.k.a Arthur) in the end.

 なーんて文章では頭抱えてしまうに違いないのだ。

いろいろ考えていく中で

 実は自分のことだけ考えるなら、たとえばひらばやしさんの AMETMulti 経由で Perl にクリップボード文字列を渡し、このへんの処理をさせてCtrl Vで書き戻すなんてことができると幸せそうな気もする(実際手はつけてないけど)。
 でもまあせっかくのことだし、「Akira32でデファクトだった半自動メール文書整形のQX版を!」と意気込んだ割に半端で放置してしまっているマクロのリベンジも含めてもう少し頑張ってみる予定。とりあえず全体のサブルーチン化による見通しの確保は済んだので、あとは正規表現関係をもう少し詰めたらバージョン0.1ぐらい上げてもよさそう。この週末はコレか……。
 ひとりブレストの場であるWikiを公開してしまう手もあるよなー。でもただでさえ精神的敷居が高いWikiだから、独自ドメインサイト内じゃなくてどこかで借りたほうが使われるかな? 某巨大掲示板のQXスレでも「Wikiねーのー」という声はぽつぽつあがるようだし。