2ch掲示板のProxomitron入門スレッド5 の517氏によって寄せられた不具合について簡単に検証してみます。
報告された不具合は、マッチ欄で $NEST(<a\s*>,</a>)
を使うと、<a\s*>
で <a href=1><a href=2>
まで消費してしまうというものです。
以下にテスト用コードを記します。
[Patterns] Name = "$NEST test1" Active = TRUE Limit = 256 Match = "$NEST((<a\s*>)\0,</a>)" Replace = "\r\n\\0 = \0\r\n"テスト用フィルタ2
[Patterns] Name = "$NEST test2" Active = TRUE Limit = 256 Match = "$NEST((<a\s[^>]+>)\0,</a>)" Replace = "\r\n\\0 = \0\r\n"htmlソース1
<a
href=
1
>
<a
href=
2
>
</a>
$NEST test1: \0 = <a href=1><a href=2>
$NEST test2: \0 = <a href=2>
<a
href=
1
>
<test>
<a
href=
2
>
</a>
$NEST test1: \0 = <a href=1><test><a href=2>
$NEST test2: \0 = <a href=2>
<a
href=
1
>
<a
href=
2
>
</a>
</a>
$NEST test1: \0 = <a href=1>
$NEST test2: \0 = <a href=1>
<a
href=
1
>
<a
href=
2
>
</a>
</a>
</a>
$NEST test1: \0 = <a href=1>
$NEST test2: \0 = <a href=1>
<a
href=
1
>
<a
href=
2
>
<a
href=
3
>
</a>
$NEST test1: \0 = <a href=1><a href=2><a href=3>
$NEST test2: \0 = <a href=3>
<a
href=
1
>
<a
href=
2
>
<a
href=
3
>
</a>
</a>
$NEST test1: \0 = <a href=1><a href=2>
$NEST test2: \0 = <a href=2>
ご覧のように、[^>]+
を使ったフィルタは問題がありませんが、*
を使ったフィルタだけ挙動がおかしいことが分かります。
ただし、終了タグの数が開始タグと同数かそれ以上であれば *
を使っても問題ないようです。
以上の動作を見て、私はまず $NEST と *
の動作原理について考えました。
これらは私の経験上の考えですが、多くは間違っていないと思います。
以上を踏まえて、$NEST(<a\s*>,</a>)
は次のような動作になっているのではと想像します。
$NEST(<a\s*>,</a>)
が start match を探す動作は次のようになっています。(\0
に </a>
が1つの場合の start match の値が代入されます)
[Patterns] Name = "$NEST emulator [\0 = start match]" Active = TRUE Limit = 256 Match = "(<a\s[^>]+>([^<]+(<(^a\s[^>]+>)[^>]+>[^<]+)+<a\s[^>]+>)+)\0*</a>" Replace = "\r\n\\0 = \0\r\n"
確実とはいえませんが、「$NEST の start match に *
があるとき、入れ子を探す過程で誤動作を起こし、start match に不正な文字列が入る」を結論としたいと思います。
不具合には違いありませんが、回避方法は分かりましたので意識して回避すれば困る事はないと思います。
*
を使わず、[^>]+
のような繰り返し表現を使う1. の繰り返し表現を使う方法がお勧めです。
「終了タグの方が開始タグより少ないという事はまずないから、何も対策しなくても良い」という考え方もあります。
が、<a name="prx">
のようなname属性値を扱うサイトでは </a>
を省略する事があり、それに誤爆する可能性があります。