$NEST(start match, [inner match,] end match)
$NEST(<a\s[^>]+>,</a>)
のように inner match を省略することが出来ます。
開始タグは正しいタグの形をしている必要はなく、$NEST(<a\s,</a>)
でも動作します。
inner match を省略した $NEST はアスタリスクで「$NEST の inner match 分」を消費した表現よりも高速に動作します。
$NEST(<a\s,</a>)
は <a\s*</a>
よりも高速に動作する、という事です。
以下のhtmlソースにマッチさせる表現を考えてみましょう。
htmlソース<div
class=
"ad"
>
<div
class=
"ad1"
>
<a
href=
"http://sample1.ad.com/"
>
広告1</a>
<a
href=
"http://sample2.ad.com/"
>
広告2</a>
<a
href=
"http://sample3.ad.com/"
>
広告3</a>
</div>
<div
class=
"ad2"
>
<a
href=
"http://sample1.ad.com/"
>
<img
src=
'http://sample1.ad.com//ad.png'
alt='広告1'
/>
</a>
<a
href=
"http://sample2.ad.com/"
>
<img
src=
'http://sample2.ad.com//ad.png'
alt='広告2'
/>
</a>
<a
href=
"http://sample3.ad.com/"
>
<img
src=
'http://sample3.ad.com//ad.png'
alt='広告3'
/>
</a>
</div>
</div>
上記ソースでは、広告は <div class="ad">...</div> で括られています。$NEST風にマッチさせるなら、以下のようになるでしょうか。
$NEST(<div\s[^>]++class=$AV(ad),</div>)
実際にテストしてみると、ん…? 上半分の広告にしかマッチしませんね。
サンプルコードにマッチした後のhtmlソース<div
class=
'ad'
>
<a
href=
'http://sample1.ad.com/'
>
<img
src=
'http://sample1.ad.com//ad.png'
alt='広告1'
/>
</a>
<a
href=
'http://sample2.ad.com/'
>
<img
src=
'http://sample2.ad.com//ad.png'
alt='広告2'
/>
</a>
<a
href=
'http://sample3.ad.com/'
>
<img
src=
'http://sample3.ad.com//ad.png'
alt='広告3'
/>
</a>
</div>
</div>
これは $NEST で陥りがちな失敗です。
$NEST は start match と end match で括られた文字列の入れ子をチェックしています。
つまり、先ほどのコードでは <div\s[^>]++class=$AV(ad)
と </div>
で括られた文字列をチェックしていたことになります。
中央にある2つのdiv要素には、class=
が存在しないため、入れ子とは見なされなかったのです。'ad'
この状況を打開するためには、div要素 に必ずある文字列を start match に入れる必要があります。
$NEST(<div\s,[^>]++class=$AV(ad)*,</div>)
<div\s
はどのdiv要素にも含まれていたので、上記表現で入れ子を正しく判定できます。
$NEST(<div,</div>)
$NEST(<div\sclass=$AV(ad),</div>)
$NEST(<div,\sclass=$AV(ad)*,</div>)
当然ですが、$NESTの入れ子チェックで問題になるのは、入れ子がある状況に限ります。
例えば、a要素 は「入れ子を作ってはいけない」とHTMLで決まっているので、$NEST(<a\s[^>]++href=$AV(http://abc.com/*),</a>)
と書いて問題ありません。