マッチングルールの "Tips and Tricks"
Previous Back to contents Next

マッチングルールは、Proxomitron の中でももっとも複雑な部分です。始めは混乱することでしょう - 特にあなたにパターンマッチングの経験がなかったなら。けれども悩むことはありません。とても簡単なルールでも、十分に役に立ちます。一つ一つやっていけば、自然に使いこなせるようになります。始めるにあたって、ここでは HTML のマッチングに関するいくつかのコツを伝授しましょう。

注:このセクションは、あなたが少しでも HTML の知識があることを前提にしています。もしその知識がなくとも、ネット上には優れたチュートリアルがたくさんあります。あるいは、あなたが独自のルールを作成するつもりがないのであれば、これからの話はまったく無視してもかまいません。

マッチングルールを見やすくする

複雑なマッチングルールは、読みにくくなってしまうものです。けれども、少しでも読みやすくするために、検索表現や置換テキストは、フィルタエディタに書く際に複数行に分けることができます。ここでの改行は、実際のフィルタには影響を与えません。ブラウザに送る HTML に、実際の改行を入れたい場合には「\n」を使用してください。

また、スペースは常にマッチするので、検索表現では、見やすくするために自由にスペースを使用することができます。ただし、これが見つけたスペースは消費されてしまうことにだけ、気を付けてください。

一般的な情報

新しいルールを作成する際には、マッチしすぎることよりも、まったくマッチしないことの方が普通です。シンプルなところから初めて、必要ならば改良していく、といったやり方がいいでしょう。そうすれば、あるルールが突然期待通りに動かなくなったときに、原因を特定するのが容易になります。

いつフィルタがマッチしているのかを知るのには、ログウィンドウを使用してください。特に、ログウィンドウの「HTML debug info」オプションを使用すると(あるいは、URLのホストネームの前に「dbug..」をつけることで)、ウェブページのソースとともに、どのフィルタが使用されたかという情報を見ることができます。これら2つは、新しいルールを作成する際には強力な助けになるでしょう。さらに役に立つのは、検索表現テストウィンドウ です。これを使用すれば、フィルタが HTML テキストをどのように加工しているのか、直接見ることができます。

HTML をカット&ペーストする

新しいフィルタを作る際に、対象の HTML から直接、検索部にカット&ペーストするのは良い方法の一つです。ここで注意しなければならないのは、行の終わりです。検索部での改行は無視されるので、HTML で2行に分かれていた以下のような表現は、

<br>
<p>

単に「<br><p>(スペースがない)」のように見えます。実際の HTML に含まれる改行コードには、マッチしなければならないので、トラブルの元になります。解決法は、「<br> (space) <p>」というように、単純にそれぞれの行の始めと終わりにスペースを入れることです(まだそこにスペースがなかった場合)。スペースは、改行コードを含めたすべての「空白」にマッチします。

タグやタグの属性値を無効にする

ブラウザは、理解できないタグやその要素は無視するので、あるタグやその要素を無効にする「簡単で汚い」けれども効果的なやり方は、それをリネームしてしまうことです。このやり方は、異なったタグの中で同じ要素が使用される場合には特に有効です。例えば、「onload」を見てみましょう。これは JavaScript を自動実行するために使われます。これは通常「<body ... >」の中で使用されますが、他の場所にあることもあります。これをストップするには...

Matching: onload=
Replace: LoadOff=

これは...

<body background="bak.gif" onload="window.open(myadd);" >

というタグを以下のように置き換えます...

<body background="bak.gif" LoadOff="window.open(myadd);" >

このルールはすごく簡単ですよね! 同時に少しリスキーでもあります。というのは 「onload=」というフレーズはタグの外で、ウェブページの地の文で使われる可能性もあるからです。でもまあ、こんなことはめったに起こりません(イコール記号を含めていることが、この危険を防ぐのに少し役立っています)。もし起こったとしても、何が起こったか容易にわかる限り、たいした問題ではないでしょう。

一鳥二石

これは、始めと終わりのタグを同時に変える、簡単なトリックです。このトリックは 「Blink to Bold」ルールの中でも使用されています。このルールにおいて、我々は「<blink>」を「<b>」に、「</blink>」を「</b>」に変えたいわけです。それでは、どうやってやっているか見てみましょう。

Matching: <\1blink>
Replace: <\1b>

\1」というメタ・キャラクタを使用することで、このルールは「<blink>」という始めのタグにも「</blink>」という終わりのタグにもマッチします。さらに、「\1」は終わりのタグのスラッシュを取り込んで、置換テキストで挿入されています。もっと安全で、しかし複雑なルールだと以下のようになるでしょう。

Matching: < ( / | )\1 blink>
Replace: <\1b>

どうしてかわかりますか? もしわからなければ、「Testing for something or nothing」を読んでみてください(訳註:下の方にあります)

タグの内容を取り込む

タグの特定の要素だけを変更して、他の部分はもとのまま残しておきたいというのは、よくあることでしょう。ここで変数「\0-9」が大活躍します。次の例で、ウェブページの背景画像を抑制する方法を見てみましょう。

Matching: <body \1 background=\w \2 >
Replace: <body \1 \2>

括弧 ( ... ) の直後に使用されていない場合は、「\0-9」 変数はアスタリスク「*」と同じように働きます。ここでは、「\1」は background 以前の要素をすべて取り込み、「\2」は以降のものをすべて取り込んでいます。置換テキストにおいて、background 要素を単に取り除くだけではなく、好きな画像に入れ替えるようにもできます。

タグに新しい要素を付け加える

これは、タグに簡単にエレメントを付け足すトリックです。もし「きちんとした」やり方をするならば、あるエレメントが存在する場合にはそれを置き換え、存在しなかった場合にだけ改めて付け足す、ということになるのでしょうが、それをするのはなかなか難しいものです。細かいことを気にせずに、ただ付け足す方がずっと簡単です。要は、ブラウザが我々の付け足したタグを採用し、最初からあった方を無視するようにしさえすればいいのです。たとえば、すべての「<img ... >」タグに、border を付け加えてみましょう。

Matching: <img \1 >
Replace: <img border=1 \1 border=1>

どうして border を2回付け足すのでしょう? 理想的には、ブラウザは、だぶった要素を見つけた場合には、最初の要素を採用して他のを無視するべきでしょう。実際、Netscape はこのように振る舞います。しかしながら、 Internet Explorer はまったく逆の振る舞いをするのです!(やれやれ)。要素を最初と最後の両方に置いてやれば、どちらのケースでもうまくいきます。ただ、ここではブラウザの独自性は、ウェブページをデザインする際に問題になるほど重要ではありません。あなたはもうご自分がどのブラウザを使うつもりでいるかおわかりでしょうから、ご自分のブラウザが期待する動作をするように設定すればいいのです。

タグの属性値に限定して取り込む

タグの属性値には、なかなかマッチさせにくいことがあります。たとえば、「<a href=... >」というタグを見てみましょう。「href」は URL を必要としますが、この URL の値は、シングルクオートやダブルクオートに囲まれていても構いませんし、クオートがなくても構いません。$AVQ(...) (Attribute Value & Quotes) コマンドを使えば、このような場合でもうまくマッチさせることができます。これは値の全部にマッチし、その際にクオートがあった場合にはそれも含みます。たとえば、URL を取り込んで \1 に入れる場合の例を見てみましょう...

<a * href=$AVQ(\1) * >

もし変数「\1」、あるいは他の \(数字) が括弧の直後におかれていた場合、その変数は括弧内でマッチしたものを取り込むようになる、ということを思い出してください。ここで、値が特定の文字列を含む場合にだけ、それを取り込むようにしてみましょう。そのために、括弧 (...) と、$AV(...) コマンドを使用します...

<a * href=( $AV(*(banner|advert|cgi)*) )\1 * >

これは、URL が「banner」や「advert」、あるいは「cgi」という文字列を含む場合にだけマッチします。これは「banner blaster」のようなルールの基礎になるものです。$AV(...) は $AVQ と似ていますが、マッチさせる中にクオートを含みませんので、実際にクオートがあるかどうかのチェックをする手間を省くことができます。なお、(クオートを含んだ)全体を取り込みたい場合には、全体を括弧で括って、直後に \1 を置くことで実現できます。こうすることで、属性値の全体を \1 に格納します。

「something or nothing」のテスト

ある特定の値が、存在してもしなくてもマッチするような表現が欲しくなることがあります。そのためには、こんなルールを使用することができます...「( something | )

これはまず「something」という語をテストします。しかし、それが見つからなかったとしてもこの表現は true を返します。なぜそうなるのでしょうか? OR シンボル(縦棒)があり、何にも挟まれないで閉じ括弧がきていることに注目してください。これは空を表現します。空の表現は常に真 (true) となり、それはいかなる文字も消費しません。これは「"something" OR nothing (何か、もしくは無)」にマッチする...と読んでください。

もし、表現が「(|something)」のように書かれていたら、「something」という単語には絶対にマッチしないことに注意してください。OR は左から右に処理してゆくので、空の表現は「something」がマッチする前に必ずマッチしてしまうのです。

この実践的な使い方の例は「( " | ) * ( " | ) 」というものです。これはクオートに囲まれているかもしれないし、囲まれていないかもしれないものをテストします。

さらに複雑な例をあげてみましょう。これは「<img ... >」タグにおいて「border」の値が存在していたら、それをつかまえて \1 に代入することができます。

<img ( * (border=\w)\1 | ) * >

アスタリスクが置かれている場所に注意してください。たとえば、「<img*(border=\w|)\1*>」という表現では、期待した動作をしないでしょう。「<img 」に続く最初の文字をスキャンする際に、もし「border」が存在していなかった場合でも、予備の表現がマッチしてしまいます。そして最初のテストを既にパスしてしまっているので、「border」が文字列の後ろで出てきた場合には、2番目のアスタリスクにマッチしてしまいます。

「AND」を使用して、複数の属性値を取り込む

アンパサンド「&」を使用すれば、タグの属性を、見つけた順番に関係なく取り込むことができます。たとえば、「<img ... >」タグを書き換えて、あなたが持っている画像と置き換え、元の「width」と「height」の値はそのまま残す、という例を考えてみましょう。その場合、以下のようにします...

Matching: <img ( (*(height=\w)\1*| ) & (*(width=\w)\2*| ) ) >
Replace: <img src="file://d|/my_pictures/shonen.gif" \1 \2 >

この場合、height は「\1」に、width は「\2」に取り込まれています。さらに上記で述べた「something or nothing」の構文を使用しているので、この表現はタグに width や height の値が存在しなくてもマッチします。その場合、該当する「\#」は単に空白になります。

「賢い」クオートの使い方

たいていの場合、「\w」はタグの属性をうまく取り込みます。しかし、それだけでは足りない場合もあります。たとえば、「<img ... >」タグの「alt」要素がスペースを含んでいることはよくあります。こんな風に...alt="this is some text" あるいは alt='also some text'。このようなものを取り込むには、ダブルクオートを使用してください。

Matching: alt=( " * " )\1

JavaScriptではさらにやっかいな問題が持ち上がります。「クオートの中にクオート」というのが普通に使われるからです。たとえば...

onmouseover="javascript:window.open( ' mywindow.html ' ); "

これを取り込むのはなかなかやっかいです。つまり、上記の文はこのように書くこともできるからです...

onmouseover= ' javascript:window.open( " mywindow.html " ); '

ここでシングルクオートの出番となります。検索表現でダブルクオートと対に使われた場合、シングルクオートは始まりのクオートに対応する終わりのクオートを探します...

Matching: onmouseover=( " * ' )\1

このルールを使えばシングルクオートでも、ダブルクオートでも、あるいはクオートが入れ子になっていたとしてもうまくいきます! けれども、この場合であれば、もっと良い方法があります。$AVQ( ) コマンドを覚えてますか? これも、すべての種類のクオートを扱うことができます(クオートがなくても問題ありません)。そして、これは属性値を取り込むためには、非常に便利です。

Matching: onmouseover=$AVQ(\1)

file URL を使用して、自分のファイルを挿入する

「file URL」 は、インターネット上の場所ではなく、あなたのハードディスク上のファイルを指し示す URL です。ブラウザは、ディスクに保存されたページを見るために「file URL」を使用しますが、同時にこれは、見ているページに、ディスク上の画像やウェブページ、さらには JavaScript などを挿入するためにも便利に使うことができます。

Proxomitron では、マッチングルール中の置換テキストに、簡単に「file URL」を挿入することができます。まず、挿入したい場所にカーソルを置き、マウスを右クリックしてコンテキストメニューを出し、「Insert file URL」を選びます。ファイルを指定するウィンドウが開きますので、挿入したいファイルを指定するだけです。

これは「file URL」を使用して背景画像を置き換える例です。

Matching: <body ( \1 background=\w | ) \2 >
Replace: <body \1 background="file://c|/pictures/background.gif" \2 >

検索表現の 「)」 と 「\2」 の間にスペースがあることに注意してください。これを忘れるのはよくあるミスの一つです。これを忘れると、「\2」は background の後ろにある部分を取り込む代わりに、括弧でマッチした部分を取り込んでしまいます。

見ている全てのページに JavaScript などを挿入する

これはあるウェブページを完全に制御してしまうやり方です。JavaScript は非常に強力な道具です。有能な右腕になります。そして、その腕はもはやあなたのものです! JavaScript などを閲覧するすべてのページに挿入したい場合は、常に存在するタグを探してください。「<html>」や「<head>」、あるいは「<body>」などはいい選択でしょう。たとえば、JavaScript のエラーメッセージがポップアップするのを防ぐルールを考えてみましょう。Netscape では、次のような JavaScript のコードをすべてのページに挿入する必要があります。「<script> this.onerror=null; </script>」。ルールは次のようになるでしょう...

Matching: <html>
Replace: <html>\n<script> onerror=null; </script>$STOP( )

これはスクリプトを <html> タグのすぐ後ろに挿入します。「\n」に注意してください。これは <html> とスクリプトの始まりとの間に改行を入れるものです。これは特に必要というわけではありませんが、あなたが結果を確かめるためにページのソースを見る場合には、それが見やすくなります。また、これを使用する際には、「Allow for multiple matches」のチェックボックスをオンにしておいたほうがいいでしょう。そうすれば、他のルールも同様にして、テキストを挿入することができるようになります。

また、$STOP( ) コマンドが使用されていることにも注目してください。これは、ページの残りの部分でこのフィルタを無効にするものです。こうすることで、同じスクリプトが複数回挿入されるのを防ぎます(特に、「multi-match」を使用している場合に重要です)。

上のような小さなスクリプトは置換テキストに直接挿入してもいいですが、長いスクリプトになると、ごちゃごちゃしてしまいがちです。よい解決法は、「<script ...>」タグに「file URL」を使用して、実際のスクリプトを記述したファイルを指定することです。たとえば、こんな感じに。

<html>\n<script src= "file://c|/scripts/myscript.js" >

見ている全てのページに何かを挿入するもっと良い方法

上記のやりかたを最初に記述したのは、ページの特定の場所(たとえば、<body ... > タグの後ろなど)に、何かを挿入するのに有効なやり方だからです。けれども、ページの最初や最後に何かを挿入すればいいというのであれば、実はもっと簡単なやり方があります。

検索部では2つの特別な値が使えます。<start><end> です。これは単純に、ページの最初、あるいは最後に置換テキストを挿入するものです。とても簡単に使えますし、何も検索をしないので効率的でもあります。<start> を使用すると、上記のルールはこのように書くことができます。

Matching: <start>
Replace: <script> onerror=null; </script>

これは JavaScript にはとても有効に働きます(そして JavaScript の機能を上書きしてしまいます。下を参照してください)。さらに、複数のマッチを許可することを考えないですみます!

JavaScript の機能を上書きしてしまう

Netscape と Internet Explorer 4.0 以降では、JavaScript をゆがめてしまう非常に効果的な方法があります。あらゆる JavaScript の機能は ── たとえそれが最初から組み込まれているものであったとしても ── 我々が望むように再定義してしまうことができます。たとえば、「alert( ... )」や「confirm( ... )」で現れるボックスを取り除きたいとします。そのためには、単に以下のようなスクリプトをページの最初に挿入すればいいのです(上記で説明した <start> を使用してください)。

<script>
function alert( ){ return(1); }
function confirm( ){ return(1); }
</script>

これで、他のスクリプトが alert や confirm のボックスを呼び出そうとたくらんでも、我々の定義した機能がその代わりに呼び出されます。「1」を返しておくことで、まだ存在するかどうかもわからないスクリプトに対して、confirm ボックスに「yes」を返したと思いこませることができます!

これは、非常に強力な考え方です。この例にある機能は、実際には何もしないにもかかわらず、十分に働きます。もっと複雑な置換機能を使用しても、特定のアラートボックスしかフィルタできなかったり、あるいは全然別のことをするだけだったりするのです。これには全く限界がありません。

これは非常に効果的なので、Proxomitron のデフォルトのルールではこのやり方を活用しています。欠点は、これが Netscape のほとんどすべてのバージョンと、IE 4.0 以降でしか使えないということです。これは IE 3.x で使われている Microsoft の JScript では機能しないのです。そのため、 Proxomitron は IE 3.0 ユーザのために、代わりのルールセットを用意しました。そのルールセットでは、通常の検索と置換を使って同等の機能を提供するようになっています。

再帰的なマッチングを使う方法

再帰的なマッチングは、ルールがそれ自身の結果に再びマッチしてしまう際に起こります。通常、これは避けなければなりません。特にそれが無限の反復 ── ルールがそれ自身に永遠にマッチし続ける ── となる場合には。けれども、正しく使えば、これは強力なテクニックになります。以下のような状況を考えてみましょう。「<script ...」と 「</script>」の間で起こるすべてのポップアップウィンドウを取り除きたい、と。JavaScript はウィンドウを開くのに「open(...)」を使用するので、ルールは以下のような物になるかもしれませんね。

Matching: <script \1 open \( * \) \2 </script>
Replace: <script \1 \2 </script>

(実際には、scope も同時に使用したいと思われるかもしれませんが、そのことについてはあとで考えてみましょう。また、括弧が持つ特別な意味をエスケープするために、「\」を使用していることに注意してください)。これは、JavaScript のなかにひとつだけ open コマンドがあった場合にはうまくいきますが、もし複数あった場合には、最初のものだけを取り除くことになります。解決法? そうですね、次の2つのことをすればいいでしょう。まず、「Allow for multiple matches」のチェックをオンにして、ルールがそれ自身の結果に対して再びマッチすることができるようにします。それから、置換テキストを以下のようにします。

Replace: \n<script \1 \2 </script>

どうしてでしょう? うっかりと無限の反復に陥ってしまうのを防ぐために、Proxomitron のマッチングエンジンは、すべてのルールがチェックされた後、1文字後ろから作業を進めていきます。つまり、この最初のルールの例では、2回目にチェックされるときは、「<script ...」ではなくて、「script ...」の部分しか見つけられないことになります。これを避けるために、単純に「改行」キャラクタを置換テキストの最初に置いたのです。最後の出力では「<script ...」の前に空行ができることになりますが、ブラウザはこれを無視します。けれどもこうすることで、ルールが、「<script ...」の部分を次の検索のときにも見つけることができるのです。最初のスペースはまた使われてしまうかもしれませんが、どちらにしてもブラウザの機能には影響を与えません。このアイディアは、単にすべての結果の前に1キャラクタを追加するというものです。

すべての「open(...)」が取り除かれたあとは、このルールはもうマッチしませんので、無限の反復に陥る危険はありません。

実際、これは有効なトリックですが、実はもっと良い(そして安全な)方法があります...

再帰的なマッチングを使わない方法

Proxomitron には、「置換スタック」と呼ばれる機能があります。これは変数「\#」を使って、複数の値をまとめるものです。おそらく、この一番簡単な使い方は、\#\0 から \9 までと同じように働くので、全く同じ場所に置いて使うことでしょう。違いは、もしこれが1回以上呼ばれた場合 ── ループで呼ばれた場合でも複数回使われた場合でも ── 値は置き換えられる代わりに、終わりに追加されていく、ということです。これを使うことで、ろくでもない循環をさけつつ、複数のアイテムにマッチさせることができます...

Match: <script (\#.open \( * \))+ \# </script>
Replace: <script \@ </script>

ここで、括弧の後にプラスを用いることで、ループを作成しています。「(...)+」は内部の表現がマッチする限り、ループを繰り返します。この例では、ループは「.open()」コマンドを検索しています。open の前にあるものはすべて最初の \# に取り込まれます。そしてループが繰り返され、次の open が見つかるまでにあったものもすべて、\# に追加されています。これが open を使い果たすまで繰り返されます。その後、それでも残ったものが2番目の \# で取り込まれています。

これはつまり、スクリプトタグの間にある open コマンド以外のものを全て取り込むことになります。置換セクションでは、\@ を使って、\# で取り込まれたものを全部はき出しています。これは再帰的なマッチとほとんど同じことをしているわけですが、こちらの方が効果的で、なおかつ危険性が少ないです(これが無限のループにはまることはあり得ないからです)。

範囲制限について

説明を簡単にするために、ここまでの例では、ウェブフィルタの範囲制限 (scope bounds)  は使用しませんでした。範囲制限は、Proxomitron のマッチングエンジンが、マッチするかどうかを調べるのにどの程度までウェブページを読み込むかをコントロールするのに使用します。(詳しい説明は、ウェブページフィルタ・エディタ をご覧ください)

範囲制限では通常、検索する範囲の始点と終点を指定します。上で使用した例で見てみると...

Matching: <script \1 open \( * \) \2 </script>
Replace: <script \1 \2 </script>

というルールは、範囲制限を使用すると以下のようになります...

Bounds: <script\s*</script>
Byte Limit: 4096
Matching: \1 open \( * \) \2
Replace: \1 \2

固定して使用されていた始まりと終わりのテキストを、単に範囲制限に持ってきただけだということに注目してください、Byte Limit は検索を終了するまでに読み込むキャラクタの最大長を指定します。ここではさらに、\1\2 を検索表現に使用して、範囲制限がマッチした最初と最後の部分を取り込んでいます。これは <script</script> を含みます。ですので、これらを置換テキストに置く必要はありません。

範囲制限を使う際に、まず覚えなければならないことがあります。つまり、検索表現 は、範囲制限でマッチするのと 全く同じだけのテキストにマッチしなければならない ということです。

つまり、範囲制限が「<HEAD>」から「</HEAD>」までマッチするのであれば、検索表現も同じくこれにマッチしなければならないのです! 上記の例で、この簡単なやり方が示されています。マッチの最初と最後を変数にして、それを置換テキストで使用するのです。

これで終わりです... とりあえず

これで、私が考えついた「コツ」はすべてです。もし、他に何かいいアイディアが浮かんだら教えてください。また、Proxomitron によって最初から提供されているルールを見ることができることも忘れないでください! それを新しいルールを作る際の参考にしてください。作りたいルールに近いものが結構あると思います。


Return to main index