皆さんは悪魔の証明という原理をご存じでしょうか?
「ないこと」を証明するのは極めて難しい。
悪魔が存在しない事を証明するには、この世の全てを知っていなければならない。
人に未知の領域がある以上、「悪魔が存在しないこと」を証明することは不可能である。
というものです。(多少、私の意見を加味しています)
反対に、「ないこと」の証明が可能な事もあります。
例えば、1+1=2 である。1+1=1 にはなり得ない。
数式のように「人が定義したもの」は人が証明できうることを示しています。
これはProxomitronのフィルタでも同じです。
Webフィルタであれば、HTML言語, JavaScript などの知識があれば「ないこと」を証明することが出来ます。
実際に証明してみましょう。
Webページを巡っていると、極たまにタイトルが存在しないページに遭遇することがあります。
これはページ制作者のミスで title要素 が抜けているのが原因です。
そこで、title要素がないときには、"no title" というタイトルを付けるフィルタを考えてみましょう。
title要素はヘッダ内の要素として定義されています。
従って、title要素は
の内に宣言されます。<head>
~</head>
(実際には、
の外にtitle要素があっても動作しますが、そのようなサイトは例外的なので考慮しないものとします)<head>
~</head>
まずは
内の領域に絞り込んでみましょう。<head>
~</head>
次に、$NESTの "inner match" でtitle要素が存在しない表現を考えます。
恐らく、これは最もよく使われる表現でしょう。
NOT関数の (^*<title>)
でtitle要素が存在しないことを確認した上で、アスタリスク で残りの全てを消費します。
これで
の内にtitle要素が存在しないことを証明できました。<head>
~</head>
最後に、
の内にtitle要素を加えます。<head>
~</head>
[Patterns] Name = "add title1" Active = TRUE URL = "$TYPE(htm)" Limit = 2048 Match = "$NEST((<head[^>]+>)\#,(^*<title>)\#,</head>)" Replace = "\@\r\n<title>no title</title>\r\n</head>"
先の記述でも問題なくマッチしますが、別の表現を考えてみましょう。
inner match を少し書き換えてみます。
初めて見る人にとっては理解しにくいかもしれませんが、頭を柔らかくして考えてみて下さい。
(^<title>)?
は <title>
ではない1文字 を表します。
NOT関数は「否定先読み」なので、(^<title>)
で見ている最初の1文字と ?
で見ている1文字は同じなのです。
これをグループ化して + で繰り返してやると、「<title>
ではない1文字」の繰り返しとなり、title要素がないことを証明できます。
最後に、
の内にtitle要素を加えて、完成です。<head>
~</head>
[Patterns] Name = "add title2" Active = TRUE URL = "$TYPE(htm)" Limit = 2048 Match = "$NEST((<head[^>]+>)\#,(((^<title>)?)+)\#,</head>)" Replace = "\@\r\n<title>no title</title>\r\n</head>"
更に、別の表現を考えてみましょう。
今回は背理法を用います。
「背理法」とはある命題を証明するためには、それと反対のケースを考え、反対のケースでは矛盾する事を証明するものです。
では、「title要素が存在しない」と反対のケースとはどんな状況でしょうか。
それは「title要素が存在する」事です。
あぁ、そこで呆れかえらないでください。
至極当然のことを説明していますが、これがとても重要なんです。
結論から言いますと、title要素が存在したときには、フィルタを止めてしまえば良いのです。
これでtitle要素が存在した時には、$STOPがフィルタを停止するようになりました。
安心して、title要素を追記できますね。
title要素が存在するのは
の内でなければならない。<head>
~</head>
よって、</head>
を検知した時にtitle要素を付け加えます。
[Patterns] Name = "add title3" Active = TRUE URL = "$TYPE(htm)" Limit = 8 Match = "(^(^<title>))|" "(^(^</head>))$SET(0=\r\n<title>no title</title>\r\n)" Replace = "$STOP()\0"
繰り返しますが、title要素は
の内にあります。<head>
~</head>
従って、もし、<title>
が存在したならば、</head>
より先にマッチするはずです。
(^(^</head>))
がマッチするときには、(^(^<title>))
がマッチしなかったことになり、title要素が存在しない事の証明に繋がります。