NabeAzzテンプレート問題パート2・解答例2

一昨日に続いて、NabeAzzテンプレート問題パート2の解答例その2を紹介します。

1.テンプレート

テンプレートのうち、HTMLのヘッダー等を除いて、問題の部分を出力するところだけを抜き出すと、以下のようになります。

<MTIgnore>xは出力する数値</MTIgnore>
<MTSetVar name="x" value="1">
<table>
<MTIgnore>二重ループ</MTIgnore>
<MTFor var="r" from="1" to="20">
  <tr>
  <MTFor var="c" from="1" to="10">
    <MTIgnore>市松模様の判断</MTIgnore>
    <td<MTIf test="($r + $c) % 2 == 1"> class="reverse"</MTIf>>
      <MTIgnore>出力する値の生成</MTIgnore>
      <MTSetVar name="out" value="$x">
      <MTIf name="x" op="%" value="3" eq="0">
        <MTSetVarBlock name="out"><b><MTGetVar name="out"></b></MTSetVarBlock>
      </MTIf>
      <MTIf name="x" like="3">
        <MTSetVarBlock name="out"><u><MTGetVar name="out"></u></MTSetVarBlock>
      </MTIf>
      <MTIf name="x" op="%" value="5" eq="0">
        <MTSetVarBlock name="out"><i><MTGetVar name="out"></i></MTSetVarBlock>
      </MTIf>
      <MTIf name="x" like="5">
        <MTSetVarBlock name="out"><s><MTGetVar name="out"></s></MTSetVarBlock>
      </MTIf>
      <MTIgnore>値の出力</MTIgnore>
      <MTGetVar name="out">
    </td>
    <MTSetVar name="x" op="++">
  </MTFor>
  </tr>
</MTFor>
</table>

2.市松模様の判断の効率化

今回の例では、2つの点を改良しています。
1つ目の改良点は、市松模様の判断の効率化です。

前回の記事では、市松模様で色を変えるセルを、以下の条件で判断していました。

  • 行番号が偶数で、かつ列番号が奇数
  • 行番号が奇数で、かつ列番号が偶数

ここで、「行番号と列番号の和」を考えてみます。
「行番号が偶数で、かつ列番号が奇数」と「行番号が奇数で、かつ列番号が偶数」のどちらであっても、行番号と列番号の和は奇数と偶数の和ですので、常に奇数になります。
したがって、「行番号と列番号の和が奇数(=和を2で割った余りが1)」という条件で、色を変えるセルを判断することができます。

MTForの二重ループで、行番号/列番号をそれぞれ変数r/cに入れるようにしています。
したがって、「rとcの和を2で割った余りが1」という条件を判断することで、色を変えるセルを決めることができます。

MTIfタグでは、「test」のモディファイアで、変数を含む式で条件判断することができます。
今の場合だと、条件式は「($r + $c) % 2 == 1」となります。

3.NabeAzzの条件判断の効率化

2つ目の改良点は、「3で割り切れる数」などの条件判断の効率化です。

前回の例では、開始タグと終了タグのそれぞれを出力する際に条件を判断していました。
しかし、この方法だと同じ条件を2回判断することになりますので、効率が良くありません。
そこで、以下のような考え方で、1回の条件判断で開始タグと終了タグを両方出力するようにしました。

  • 変数outに、最終的に出力するものを保存するとします。
    例えば、3を出力する場合、3は3で割り切れて、かつ3を含みますので、変数outの値が最終的に「<u><b>3</b></u>」になるようにします。
  • まず、変数outに、出力する数字を代入します。
  • 数字が3で割り切れるなら、変数outの前に「<b>」を連結し、後ろに「</b>」を連結して、変数outに代入しなおします。
  • 数字に3が含まれるなら、変数outの前に「<u>」を連結し、後ろに「</u>」を連結して、変数outに代入しなおします。
  • 数字が5で割り切れるなら、変数outの前に「<i>」を連結し、後ろに「</i>」を連結して、変数outに代入しなおします。
  • 数字に5が含まれるなら、変数outの前に「<s>」を連結し、後ろに「</s>」を連結して、変数outに代入しなおします。
  • 変数outの値を出力します。

例えば、3を出力する場合だと、上記の手順によって、変数outの値は以下のように変化していきます。

処理条件の真偽処理後の変数outの値
変数outに数字を代入 3
3で割り切れる?<b>3</b>
3を含む?<u><b>3</b></u>
5で割り切れる?×<u><b>3</b></u>
5を含む?×<u><b>3</b></u>

ここでのポイントは、「変数の前に値を連結する」ことと、「変数を処理した結果を元の変数に代入しなおす」いう点です。

通常のテンプレートだと、すでに出力したものの前に何かを挿入することはできません。
しかし、変数を使うと、上の例のように、変数の値の前に別の値を挿入して、その値を元の変数に代入しなおすことができます。
この手法は、覚えておくと何かと使い道があると思います。