YONのドバトブログ

YONの土鳩ブログ

ゲーム好きの鳩"YON"がツイッターでは言い切れないことについて書き連ねるブログ

内容解説「はてなブログの下線付き自動リンクを除去するWordマクロ」

導入方法に関しては以下の記事を参照。


この記事では、配布しているWordファイルに入っているマクロの内容を解説するこちらのリンク先(2022/01/22共有停止)にあるテキストファイルにマクロの全文があるので、適宜参照しながら読んでほしい。

マクロファイルのDLに抵抗がある人は、リンク先(2022/01/22共有停止)テキストファイルを閲覧してマクロ全文をチェックした上で、DLして自分で作成したマクロファイルにコピペして使ってほしい(この記事に全文をスクロールバー付きで載せようとしたら、字数制限に引っかかってしまった)。

全文を見ると、とんでもないアホコードかと思われるかもしれないが、一応それなりに長い文章に対しても一瞬で動作することは確認している。重複箇所が非常に多いのでもっと簡略化できるはずなのだが、いまいち上手くいかないのでとりあえずこれで我慢してほしい。

 

解説

このプログラムは置換作業の連続だが、ワイルドカードを使用しない置換とワイルドカードを使用した置換の2種類の置換を行っている。

ワイルドカードを使用しない置換
' <p>, </p> パラグラフタグ処理
    With Selection.Find
        .Text = "<p>"
        .Replacement.Text = "<p>[]"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchByte = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchWildcards = False
        .MatchFuzzy = False
    End With
    Selection.Find.Execute Replace:=wdReplaceAll

例えばこの部分はワイルドカードを使わない置換を行っている。つまり、通常の置換作業だ。重要な部分を太字にしておいた。

.Text = "<p>"
.Replacement.Text = "<p>[]"

この部分は、"<p>"という部分を"<p>[]"に置換することを示している。つまり、この部分に置換したい文字を入力すればプログラムの内容を書き換えることができる。

冒頭の"With Selection.Find"から"Selection.Find.Execute Replace:=wdReplaceAll"までで1つの区切りになっている。

 

ワイルドカードを用いた置換

(注)モバイル端末から閲覧すると一部記号が表示されない場合がある

' <p class="openBtn">等のタグ処理
    With Selection.Find
        .Text = "(<p) (*)(>)"
        .Replacement.Text = "<p >[]"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchByte = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchFuzzy = False
        .MatchWildcards = True
    End With
    Selection.Find.Execute Replace:=wdReplaceAll

例えばこの部分はワイルドカードを使った置換を行っている。ワイルドカードについてはこのページが参考になる。Wordで使う正規表現のようなものだ。

.Text = "(<p) (*)(>)"

この部分は置換される文字を示している。(<p), , (*), (>)の4つの部分に分かれている(2つ目は半角スペース)。*は任意の文字列を示し、はワイルドカードとして認識される<, >を通常の記号として認識させるために入れている。そして、

.Replacement.Text = "<p >[]"

こちらのは、()に入った3つの部分の内2番目の要素を示している。つまり、例えば"<p class="openBtn">"という部分を置換すると、はclass="openBtn"という部分を示すことになり、置換後の文字列は"<p class="openBtn">[]"となる。

こちらも同じく、冒頭の"With Selection.Find"から"Selection.Find.Execute Replace:=wdReplaceAll"までで1つの区切りになっているので、処理を付け加える場合はこの部分をコピペして編集すれば良い。

 

その他の処理
' 既存の[]を全削除

この工程は、一部分にこのマクロを実行した文章や、既に一部に[]を入力した文章に対してもマクロを実行できるように入れている。

 

' <p>?</p> 空白行処理

はてなブログでは、空行に"<p> </p>"という記述が入り空白行となる。タグの間に空白文字が入っているのだが、これをWordにコピペすると空白文字が消えてしまい、はてなブログのHTML編集メニューに戻すと空白行が丸々消えてしまう。

これを防ぐために、"<p> </p>"という記述を"<br>"という改行処理に直し、HTML編集メニューに戻した際も空白行を消さないようにしている。"<br>"タグは一度プレビューを開くと"<p> </p>"という記述に戻る。

 

' 文字装飾終了タグ処理

太字や(忌々しくない通常の)下線などの文字装飾のタグ<strong></strong>や<span></span>の内部に[]が入ってしまうと、[]の効果が装飾内だけに及び、外には及ばなくなってしまう。通常は考慮しなくてよく、この文章のように<code>タグなどにより文中に[]が度々登場し、しかも文字装飾と絡む場合にしか必要ない例外的処理だが、一応入れている。

 

' [][]を削除

[]が2つ重なっている箇所は不要なので、削除する。

 

デバッグのヒント

マクロを実行したり編集したりしたが、うまく自動キーワードリンクが消えない、という場合はここを見てほしい。私がつまずいた部分を記述してある。

  • 文章全体、あるいは見出し間において、ちゃんと[]が偶数個になっているか?偶数個になっていない場合、[]で文章を囲えていない。勿論、この記事のように文中に[]が登場する場合は例外だ
  • 文章の中に変わったタグはないか?例えば<code></code>などのタグが挟まっていると[]が機能しない*1
  • []が<strong></strong>タグなどの内部に入っていないか?</strong>タグで一旦自動リンク停止構文の効果が切れてしまうので、その後にもう1つ[]を挿入する必要がある
  • ワイルドカードの指定は合っているか?実際にWordの置換メニューで置換できるか確認してみよう。置換できるなら、「マクロの記録」を行って手動で置換を行って置換処理マクロを作成し、後で元のマクロに合成しても良い。

 

おまけ <pre>タグの処理

注意事項でも書いたが、このマクロは<pre></pre>タグが存在する場合は上手く動作しない*2。<pre>タグの範囲外だけ逐一コピペしてマクロを実行するか、全体にマクロをかけた後に<pre>タグ内部で置換処理をして[]を除くしかない(Word上で置換する範囲を選択した状態で「すべて置換」していけばOK)。

<pre>タグ内部にある</span>や</strong>などの文字装飾タグを一時的に別の文字に置き換えて例外処理しようとしたり、<pre>タグ内部の[]をマクロ処理で除こうとしたりしたものの、結局<pre></pre>で囲われる領域が2つ以上ある場合に<pre></pre>内部を判別する方法が思いつかず、失敗した*3。おまけファイルには失敗した残骸プログラムを入れてある。機会があればまた色々試してみるが、何か良い方法を知っていたら教えて頂きたい。

f:id:YON_4:20161016133249p:plain

*1:ちなみに、<code>タグが注釈内部にあると注釈も機能しなくなる。こればかりははてなブログの仕様みたいなので逐一編集するしかない

*2:正確に言うと、<pre>タグのような、記号をそのまま表示するタグ内部に文字装飾がある文章全体にマクロを適用すると、自動リンク停止構文が表示されたまま残ってしまう。皮肉なことに、この記事自体が好例となっている

*3:例えば<pre> A </pre> B <pre> C </pre>とある場合、実際に<pre>タグの効果が及ぶのはAとCだけであるが、ワイルドカードによる検索をかけるとBも左端の<pre>と右端の</pre>の間にあるため、<pre>タグの内部に存在する扱いになってしまう