マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

例のマークシートのアレを実際にzrefでやってみた話

というわけで、実際にやってみた。

問題の整理

元ネタ。

某マクロツイーターのzref関連の解説記事。

実装

変更部分のコードのみを示す。

%%↓★以下を追加
\RequirePackage{zref}
\zref@newprop{countermark}[1]{0}
\zref@newlist{marksheet}
\zref@addprop{marksheet}{countermark}

%%↓\markboxletter の実装を修正
\newcommand{\markboxletter}[2][]{%
  \stepcounter{countermark}%
  \ifx{#1%
    }{}{}%
  \else
    \ExpandArgs{nx}\zref@setcurrent{countermark}{\thecountermark}%★変更
    \zref@labelbylist{#1}{marksheet}%★変更
  \fi
  \katakana{countermark}%
  \setcounter{itermark}{1}%
  \whiledo{\value{itermark}<#2}{%
    \stepcounter{countermark}%
    \katakana{countermark}%
    \addtocounter{itermark}{1}%
  }%
}

%%↓\refmarkboxletter の実装を修正
\newcommand{\refmarkboxletter}[2][]{%
  \setcounter{tempcountermark}{\zref@extract{#1}{countermark}}%★変更
  \setcounter{itermark}{0}%
  \whiledo{\value{itermark}<#2}{%
    \katakana{tempcountermark}%
    \stepcounter{tempcountermark}%
    \addtocounter{itermark}{1}%
  }%
}

変更内容は以下の通り。

  • “★”の箇所の追加・修正。
  • LaTeXカーネルの相互参照機能は使わないので\refstepcounterを全部\stepcounterに変更した。

zrefする場合の問題点

この実装の中で、特にTeX言語初級者にとって一番難しいと思われるのは次の箇所である。

    \ExpandArgs{nx}\zref@setcurrent{countermark}{\thecountermark}%★変更

ここでは「LaTeXのcountermarkカウンタ」の現在の値を「zrefのcountermarkプロパティ」に設定しようとしている。ところが、zrefのプロパティは「トークン列を格納する」ものであるため、カウンタの現在の値(を表すトークン列)を得ようとすると、何らかの展開制御が必要になってしまう。具体的には次のようなコードを実行する必要がある。

\zref@setcurrent{countermark}{\thecountermark の完全展開】}

TeX言語の展開制御に慣れている人であれば、次のような「踏み台パターン」を用いたコードを書くのは容易であろう。

\edef\next{%
  \noexpand\zref@setcurrent{countermark}{\thecountermark}}
\next

しかし、所望の展開パターンからこのコードへ到達する過程は直観的ではなく、TeX言語初級者にとって大変な困難を伴うものであることは間違いない。zrefは別に「初級開発者向け」のパッケージではないので仕方がないことではあるが、もう少しどうにかならないものだろうか。

そこでここでは「\ExpandArgs を使う」という方法を採用してみた。\ExpandArgsは2022-06-01版のカーネルで追加された命令で「expl3の直観的な展開制御をTeX言語のコードで使えるようにする」ためのものである。今の場合は次のように考える。

  • 以下の\zref@setcurrentの呼出の引数について、展開制御をしたい。
    \zref@setcurrent{countermark}{\thecountermark}
  • 第1引数のcountermarkはそのままにしたい → n指定
  • 第2引数の\thecountermarkは完全展開したい → x指定
  • 従って、\ExpandArgs{nx}\zref@setcurrentの前に置けばよい。

その結果が本節の冒頭に示したコードになる。

    \ExpandArgs{nx}\zref@setcurrent{countermark}{\thecountermark}%★変更

まとめ

  • やっぱりzrefパッケージは便利
  • 初級者が展開制御したい場合は\ExpandArgsが便利かもしれない